Coverage Report

Created: 2023-03-26 07:33

/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
32
_gnutls_gost_vko_key(gnutls_pk_params_st * pub,
33
         gnutls_pk_params_st * priv,
34
         gnutls_datum_t * ukm,
35
         gnutls_digest_algorithm_t digalg, gnutls_datum_t * kek)
36
0
{
37
0
  gnutls_datum_t tmp_vko_key;
38
0
  int ret;
39
40
0
  ret = _gnutls_pk_derive_nonce(pub->algo, &tmp_vko_key, priv, pub, ukm);
41
0
  if (ret < 0)
42
0
    return gnutls_assert_val(ret);
43
44
0
  kek->size = gnutls_hash_get_len(digalg);
45
0
  kek->data = gnutls_malloc(kek->size);
46
0
  if (kek->data == NULL) {
47
0
    gnutls_assert();
48
0
    ret = GNUTLS_E_MEMORY_ERROR;
49
0
    goto cleanup;
50
0
  }
51
52
0
  ret =
53
0
      gnutls_hash_fast(digalg, tmp_vko_key.data, tmp_vko_key.size,
54
0
           kek->data);
55
0
  if (ret < 0) {
56
0
    gnutls_assert();
57
0
    _gnutls_free_datum(kek);
58
0
    goto cleanup;
59
0
  }
60
61
0
  ret = 0;
62
63
0
 cleanup:
64
0
  _gnutls_free_temp_key_datum(&tmp_vko_key);
65
66
0
  return ret;
67
0
}
68
69
static const gnutls_datum_t zero_data = { NULL, 0 };
70
71
int
72
_gnutls_gost_keytrans_encrypt(gnutls_pk_params_st * pub,
73
            gnutls_pk_params_st * priv,
74
            gnutls_datum_t * cek,
75
            gnutls_datum_t * ukm, gnutls_datum_t * out)
76
0
{
77
0
  int ret;
78
0
  gnutls_datum_t kek;
79
0
  gnutls_datum_t enc, imit;
80
0
  gnutls_digest_algorithm_t digalg;
81
0
  asn1_node kx;
82
83
0
  if (pub->algo == GNUTLS_PK_GOST_01)
84
0
    digalg = GNUTLS_DIG_GOSTR_94;
85
0
  else
86
0
    digalg = GNUTLS_DIG_STREEBOG_256;
87
88
0
  ret = _gnutls_gost_vko_key(pub, priv, ukm, digalg, &kek);
89
0
  if (ret < 0) {
90
0
    gnutls_assert();
91
92
0
    return ret;
93
0
  }
94
95
0
  ret = _gnutls_gost_key_wrap(pub->gost_params, &kek, ukm, cek,
96
0
            &enc, &imit);
97
0
  _gnutls_free_key_datum(&kek);
98
0
  if (ret < 0) {
99
0
    gnutls_assert();
100
101
0
    return ret;
102
0
  }
103
104
0
  ret = asn1_create_element(_gnutls_get_gnutls_asn(),
105
0
          "GNUTLS.GostR3410-KeyTransport", &kx);
106
0
  if (ret != ASN1_SUCCESS) {
107
0
    gnutls_assert();
108
0
    ret = _gnutls_asn2err(ret);
109
0
    _gnutls_free_datum(&enc);
110
0
    _gnutls_free_datum(&imit);
111
112
0
    return ret;
113
0
  }
114
115
0
  ret = _gnutls_x509_write_value(kx, "transportParameters.ukm", ukm);
116
0
  if (ret < 0) {
117
0
    gnutls_assert();
118
0
    goto cleanup;
119
0
  }
120
121
0
  ret = _gnutls_x509_encode_and_copy_PKI_params(kx,
122
0
                  "transportParameters.ephemeralPublicKey",
123
0
                  priv);
124
0
  if (ret < 0) {
125
0
    gnutls_assert();
126
0
    goto cleanup;
127
0
  }
128
129
0
  if ((ret =
130
0
       asn1_write_value(kx, "transportParameters.encryptionParamSet",
131
0
            gnutls_gost_paramset_get_oid(pub->gost_params),
132
0
            1)) != ASN1_SUCCESS) {
133
0
    gnutls_assert();
134
0
    ret = _gnutls_asn2err(ret);
135
0
    goto cleanup;
136
0
  }
137
138
0
  ret =
139
0
      _gnutls_x509_write_value(kx, "sessionEncryptedKey.encryptedKey",
140
0
             &enc);
141
0
  if (ret < 0) {
142
0
    gnutls_assert();
143
0
    goto cleanup;
144
0
  }
145
146
0
  ret =
147
0
      _gnutls_x509_write_value(kx, "sessionEncryptedKey.maskKey",
148
0
             &zero_data);
149
0
  if (ret < 0) {
150
0
    gnutls_assert();
151
0
    goto cleanup;
152
0
  }
153
0
  ret = _gnutls_x509_write_value(kx, "sessionEncryptedKey.macKey", &imit);
154
0
  if (ret < 0) {
155
0
    gnutls_assert();
156
0
    goto cleanup;
157
0
  }
158
159
0
  ret = _gnutls_x509_der_encode(kx, "", out, 0);
160
0
  if (ret < 0) {
161
0
    gnutls_assert();
162
0
    goto cleanup;
163
0
  }
164
165
0
  ret = 0;
166
167
0
 cleanup:
168
0
  asn1_delete_structure(&kx);
169
0
  _gnutls_free_datum(&enc);
170
0
  _gnutls_free_datum(&imit);
171
172
0
  return ret;
173
0
}
174
175
int
176
_gnutls_gost_keytrans_decrypt(gnutls_pk_params_st * priv,
177
            gnutls_datum_t * cek,
178
            gnutls_datum_t * ukm, gnutls_datum_t * out)
179
0
{
180
0
  int ret;
181
0
  asn1_node kx;
182
0
  gnutls_pk_params_st pub;
183
0
  gnutls_datum_t kek;
184
0
  gnutls_datum_t ukm2, enc, imit;
185
0
  char oid[MAX_OID_SIZE];
186
0
  int oid_size;
187
0
  gnutls_digest_algorithm_t digalg;
188
189
0
  if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
190
0
               "GNUTLS.GostR3410-KeyTransport",
191
0
               &kx)) != ASN1_SUCCESS) {
192
0
    gnutls_assert();
193
0
    ret = _gnutls_asn2err(ret);
194
195
0
    return ret;
196
0
  }
197
198
0
  ret = _asn1_strict_der_decode(&kx, cek->data, cek->size, NULL);
199
0
  if (ret != ASN1_SUCCESS) {
200
0
    gnutls_assert();
201
0
    ret = _gnutls_asn2err(ret);
202
0
    asn1_delete_structure(&kx);
203
204
0
    return ret;
205
0
  }
206
207
0
  ret = _gnutls_get_asn_mpis(kx,
208
0
           "transportParameters.ephemeralPublicKey",
209
0
           &pub);
210
0
  if (ret < 0) {
211
0
    gnutls_assert();
212
0
    goto cleanup;
213
0
  }
214
215
0
  if (pub.algo != priv->algo ||
216
0
      pub.gost_params != priv->gost_params || pub.curve != priv->curve) {
217
0
    gnutls_assert();
218
0
    ret = GNUTLS_E_ILLEGAL_PARAMETER;
219
0
    goto cleanup;
220
0
  }
221
222
0
  oid_size = sizeof(oid);
223
0
  ret =
224
0
      asn1_read_value(kx, "transportParameters.encryptionParamSet", oid,
225
0
          &oid_size);
226
0
  if (ret != ASN1_SUCCESS) {
227
0
    gnutls_assert();
228
0
    ret = _gnutls_asn2err(ret);
229
0
    goto cleanup;
230
0
  }
231
232
0
  if (gnutls_oid_to_gost_paramset(oid) != priv->gost_params) {
233
0
    gnutls_assert();
234
0
    ret = GNUTLS_E_ASN1_DER_ERROR;
235
0
    goto cleanup;
236
0
  }
237
238
0
  ret = _gnutls_x509_read_value(kx, "transportParameters.ukm", &ukm2);
239
0
  if (ret < 0) {
240
0
    gnutls_assert();
241
0
    goto cleanup;
242
0
  }
243
244
  /* Kind of strange design. For TLS UKM is calculated as a hash of
245
   * client and server random. At the same time UKM is transmitted as a
246
   * part of KeyTransport structure. At this point we have to compare
247
   * them to check that they are equal. This does not result in an oracle
248
   * of any kind as all values are transmitted in cleartext. Returning
249
   * that this point won't give any information to the attacker.
250
   */
251
0
  if (ukm2.size != ukm->size
252
0
      || memcmp(ukm2.data, ukm->data, ukm->size) != 0) {
253
0
    gnutls_assert();
254
0
    _gnutls_free_datum(&ukm2);
255
0
    ret = GNUTLS_E_DECRYPTION_FAILED;
256
0
    goto cleanup;
257
0
  }
258
0
  _gnutls_free_datum(&ukm2);
259
260
0
  ret = _gnutls_x509_read_value(kx, "sessionEncryptedKey.encryptedKey",
261
0
              &enc);
262
0
  if (ret < 0) {
263
0
    gnutls_assert();
264
0
    goto cleanup;
265
0
  }
266
267
0
  ret = _gnutls_x509_read_value(kx, "sessionEncryptedKey.macKey", &imit);
268
0
  if (ret < 0) {
269
0
    gnutls_assert();
270
0
    _gnutls_free_datum(&enc);
271
0
    goto cleanup;
272
0
  }
273
274
0
  if (pub.algo == GNUTLS_PK_GOST_01)
275
0
    digalg = GNUTLS_DIG_GOSTR_94;
276
0
  else
277
0
    digalg = GNUTLS_DIG_STREEBOG_256;
278
279
0
  ret = _gnutls_gost_vko_key(&pub, priv, ukm, digalg, &kek);
280
0
  if (ret < 0) {
281
0
    gnutls_assert();
282
0
    goto cleanup2;
283
0
  }
284
285
0
  ret = _gnutls_gost_key_unwrap(pub.gost_params, &kek, ukm,
286
0
              &enc, &imit, out);
287
0
  _gnutls_free_key_datum(&kek);
288
289
0
  if (ret < 0) {
290
0
    gnutls_assert();
291
0
    goto cleanup2;
292
0
  }
293
294
0
  ret = 0;
295
296
0
 cleanup2:
297
0
  _gnutls_free_datum(&imit);
298
0
  _gnutls_free_datum(&enc);
299
0
 cleanup:
300
0
  gnutls_pk_params_release(&pub);
301
0
  asn1_delete_structure(&kx);
302
303
0
  return ret;
304
0
}