Coverage Report

Created: 2025-03-18 06:55

/src/gnutls/lib/x509/pkcs12_encr.c
Line
Count
Source (jump to first uncovered line)
1
/* minip12.c - A mini pkcs-12 implementation (modified for gnutls)
2
 *
3
 * Copyright (C) 2002-2012 Free Software Foundation, Inc.
4
 * Copyright (C) 2017 Red Hat, Inc.
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "gnutls_int.h"
24
25
#include "mpi.h"
26
#include "errors.h"
27
#include "x509_int.h"
28
#include "algorithms.h"
29
30
0
#define MAX_PASS_LEN 8192
31
0
#define MAX_V_SIZE 128
32
/* ID should be:
33
 * 3 for MAC
34
 * 2 for IV
35
 * 1 for encryption key
36
 *
37
 * Note that this function produces different key for the
38
 * NULL password, and for the password with zero length.
39
 */
40
int _gnutls_pkcs12_string_to_key(const mac_entry_st *me, unsigned int id,
41
         const uint8_t *salt, unsigned int salt_size,
42
         unsigned int iter, const char *pw,
43
         unsigned int req_keylen, uint8_t *keybuf)
44
0
{
45
0
  int rc;
46
0
  unsigned int i, j;
47
0
  digest_hd_st md;
48
0
  bigint_t num_b1 = NULL, num_ij = NULL;
49
0
  bigint_t v_mpi = NULL;
50
0
  unsigned int pwlen;
51
0
  uint8_t hash[MAX_HASH_SIZE], buf_b[MAX_V_SIZE],
52
0
    buf_i[MAX_PASS_LEN + MAX_V_SIZE], *p;
53
0
  uint8_t d[MAX_V_SIZE];
54
0
  size_t cur_keylen;
55
0
  size_t n, m, plen, i_size;
56
0
  size_t slen;
57
0
  gnutls_datum_t ucs2 = { NULL, 0 };
58
0
  unsigned mac_len;
59
0
  uint8_t v_val[MAX_V_SIZE + 1];
60
0
  unsigned v_size = 0;
61
62
0
  switch (me->id) {
63
0
  case GNUTLS_DIG_GOSTR_94:
64
0
    v_size = 32;
65
0
    break;
66
0
  case GNUTLS_DIG_SHA1:
67
0
  case GNUTLS_DIG_SHA224:
68
0
  case GNUTLS_DIG_SHA256:
69
0
  case GNUTLS_DIG_STREEBOG_256:
70
0
  case GNUTLS_DIG_STREEBOG_512:
71
0
    v_size = 64;
72
0
    break;
73
0
  case GNUTLS_DIG_SHA384:
74
0
  case GNUTLS_DIG_SHA512:
75
0
    v_size = 128;
76
0
    break;
77
0
  default:
78
0
    break;
79
0
  }
80
81
0
  if (v_size == 0 || v_size > MAX_V_SIZE)
82
0
    return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
83
84
0
  memset(v_val, 0, sizeof(v_val));
85
0
  v_val[0] = 0x01; /* make it be 2^64 or 2^128 */
86
87
0
  cur_keylen = 0;
88
89
0
  if (pw) {
90
0
    pwlen = strlen(pw);
91
92
0
    if (pwlen == 0) {
93
0
      ucs2.data = gnutls_calloc(1, 2);
94
0
      if (ucs2.data == NULL)
95
0
        return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
96
0
      ucs2.size = 2;
97
0
    } else {
98
0
      rc = _gnutls_utf8_to_ucs2(pw, pwlen, &ucs2, 1);
99
0
      if (rc < 0)
100
0
        return gnutls_assert_val(rc);
101
102
      /* include terminating zero */
103
0
      ucs2.size += 2;
104
0
    }
105
0
    pwlen = ucs2.size;
106
0
    pw = (char *)ucs2.data;
107
0
  } else {
108
0
    pwlen = 0;
109
0
  }
110
111
0
  if (pwlen > MAX_PASS_LEN) {
112
0
    rc = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
113
0
    goto cleanup;
114
0
  }
115
116
0
  rc = _gnutls_mpi_init_scan(&v_mpi, v_val, v_size + 1);
117
0
  if (rc < 0) {
118
0
    gnutls_assert();
119
0
    goto cleanup;
120
0
  }
121
122
  /* Store salt and password in BUF_I */
123
0
  slen = ((salt_size + v_size - 1) / v_size) * v_size;
124
0
  plen = ((pwlen + v_size - 1) / v_size) * v_size;
125
0
  i_size = slen + plen;
126
127
0
  if (i_size > sizeof(buf_i)) {
128
0
    rc = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
129
0
    goto cleanup;
130
0
  }
131
132
0
  p = buf_i;
133
0
  for (i = 0; i < slen; i++)
134
0
    *p++ = salt[i % salt_size];
135
136
0
  if (pw) {
137
0
    for (i = j = 0; i < plen; i += 2) {
138
0
      *p++ = pw[j];
139
0
      *p++ = pw[j + 1];
140
0
      j += 2;
141
0
      if (j >= pwlen)
142
0
        j = 0;
143
0
    }
144
0
  } else {
145
0
    memset(p, 0, plen);
146
0
  }
147
148
0
  mac_len = _gnutls_mac_get_algo_len(me);
149
0
  assert(mac_len != 0);
150
151
0
  for (;;) {
152
0
    rc = _gnutls_hash_init(&md, me);
153
0
    if (rc < 0) {
154
0
      gnutls_assert();
155
0
      goto cleanup;
156
0
    }
157
0
    memset(d, id & 0xff, v_size);
158
0
    _gnutls_hash(&md, d, v_size);
159
0
    _gnutls_hash(&md, buf_i, i_size);
160
0
    _gnutls_hash_deinit(&md, hash);
161
0
    for (i = 1; i < iter; i++) {
162
0
      rc = _gnutls_hash_fast(
163
0
        (gnutls_digest_algorithm_t)me->id, hash,
164
0
        mac_len, hash);
165
0
      if (rc < 0) {
166
0
        gnutls_assert();
167
0
        goto cleanup;
168
0
      }
169
0
    }
170
0
    for (i = 0; i < mac_len && cur_keylen < req_keylen; i++)
171
0
      keybuf[cur_keylen++] = hash[i];
172
0
    if (cur_keylen == req_keylen) {
173
0
      rc = 0; /* ready */
174
0
      goto cleanup;
175
0
    }
176
177
    /* need more bytes. */
178
0
    for (i = 0; i < v_size; i++)
179
0
      buf_b[i] = hash[i % mac_len];
180
0
    n = v_size;
181
0
    rc = _gnutls_mpi_init_scan(&num_b1, buf_b, n);
182
0
    if (rc < 0) {
183
0
      gnutls_assert();
184
0
      goto cleanup;
185
0
    }
186
187
0
    rc = _gnutls_mpi_add_ui(num_b1, num_b1, 1);
188
0
    if (rc < 0) {
189
0
      gnutls_assert();
190
0
      goto cleanup;
191
0
    }
192
193
0
    for (i = 0; i < i_size; i += v_size) {
194
0
      n = v_size;
195
0
      rc = _gnutls_mpi_init_scan(&num_ij, buf_i + i, n);
196
0
      if (rc < 0) {
197
0
        gnutls_assert();
198
0
        goto cleanup;
199
0
      }
200
201
0
      rc = _gnutls_mpi_addm(num_ij, num_ij, num_b1, v_mpi);
202
0
      if (rc < 0) {
203
0
        gnutls_assert();
204
0
        goto cleanup;
205
0
      }
206
207
0
      n = v_size;
208
0
      m = (_gnutls_mpi_get_nbits(num_ij) + 7) / 8;
209
210
0
      memset(buf_i + i, 0, n - m);
211
0
      rc = _gnutls_mpi_print(num_ij, buf_i + i + n - m, &n);
212
0
      if (rc < 0) {
213
0
        gnutls_assert();
214
0
        goto cleanup;
215
0
      }
216
0
      _gnutls_mpi_release(&num_ij);
217
0
    }
218
0
  }
219
0
cleanup:
220
0
  _gnutls_mpi_release(&num_ij);
221
0
  _gnutls_mpi_release(&num_b1);
222
0
  _gnutls_mpi_release(&v_mpi);
223
0
  gnutls_free(ucs2.data);
224
225
0
  return rc;
226
0
}