/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 | } |