Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / lib / gnutls_cipher_int.c
1 /*
2  * Copyright (C) 2009-2013 Free Software Foundation, Inc.
3  * Copyright (C) 2013 Nikos Mavrogiannopoulos
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>
21  *
22  */
23
24 #include <gnutls_int.h>
25 #include <gnutls_errors.h>
26 #include <gnutls_cipher_int.h>
27 #include <gnutls_datum.h>
28 #include <gnutls/crypto.h>
29 #include <crypto.h>
30 #include <fips.h>
31 #include <algorithms.h>
32
33 #define SR(x, cleanup) if ( (x)<0 ) { \
34   gnutls_assert(); \
35   ret = GNUTLS_E_INTERNAL_ERROR; \
36   goto cleanup; \
37   }
38
39 /* Returns true(non-zero) or false(0) if the 
40  * provided cipher exists
41  */
42 int _gnutls_cipher_exists(gnutls_cipher_algorithm_t cipher)
43 {
44         const gnutls_crypto_cipher_st *cc;
45         int ret;
46
47         /* All the other ciphers are disabled on the back-end library.
48          * The NULL needs to be detected here as it is merely a placeholder
49          * rather than an actual cipher.
50          */
51         if (cipher == GNUTLS_CIPHER_NULL) {
52                 if (_gnutls_fips_mode_enabled() == 0)
53                         return 1;
54                 else
55                         return 0;
56         }
57
58         cc = _gnutls_get_crypto_cipher(cipher);
59         if (cc != NULL)
60                 return 1;
61
62         ret = _gnutls_cipher_ops.exists(cipher);
63         return ret;
64 }
65
66 int
67 _gnutls_cipher_init(cipher_hd_st * handle, const cipher_entry_st * e,
68                     const gnutls_datum_t * key, const gnutls_datum_t * iv,
69                     int enc)
70 {
71         int ret = GNUTLS_E_INTERNAL_ERROR;
72         const gnutls_crypto_cipher_st *cc = NULL;
73
74         if (unlikely(e == NULL || e->id == GNUTLS_CIPHER_NULL))
75                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
76                 
77         FAIL_IF_LIB_ERROR;
78
79         handle->e = e;
80
81         /* check if a cipher has been registered
82          */
83         cc = _gnutls_get_crypto_cipher(e->id);
84         if (cc != NULL) {
85                 handle->encrypt = cc->encrypt;
86                 handle->decrypt = cc->decrypt;
87                 handle->deinit = cc->deinit;
88                 handle->auth = cc->auth;
89                 handle->tag = cc->tag;
90                 handle->setiv = cc->setiv;
91
92                 SR(cc->init(e->id, &handle->handle, enc), cc_cleanup);
93                 SR(cc->setkey(handle->handle, key->data, key->size),
94                    cc_cleanup);
95                 if (iv) {
96                         SR(cc->setiv(handle->handle, iv->data, iv->size),
97                            cc_cleanup);
98                 }
99
100                 return 0;
101         }
102
103         handle->encrypt = _gnutls_cipher_ops.encrypt;
104         handle->decrypt = _gnutls_cipher_ops.decrypt;
105         handle->deinit = _gnutls_cipher_ops.deinit;
106         handle->auth = _gnutls_cipher_ops.auth;
107         handle->tag = _gnutls_cipher_ops.tag;
108         handle->setiv = _gnutls_cipher_ops.setiv;
109
110         /* otherwise use generic cipher interface
111          */
112         ret = _gnutls_cipher_ops.init(e->id, &handle->handle, enc);
113         if (ret < 0) {
114                 gnutls_assert();
115                 return ret;
116         }
117
118         ret =
119             _gnutls_cipher_ops.setkey(handle->handle, key->data,
120                                       key->size);
121         if (ret < 0) {
122                 gnutls_assert();
123                 goto cc_cleanup;
124         }
125
126         if (iv) {
127                 ret =
128                     _gnutls_cipher_ops.setiv(handle->handle, iv->data,
129                                              iv->size);
130                 if (ret < 0) {
131                         gnutls_assert();
132                         goto cc_cleanup;
133                 }
134         }
135
136         return 0;
137
138       cc_cleanup:
139
140         if (handle->handle)
141                 handle->deinit(handle->handle);
142
143         return ret;
144 }
145
146 /* Auth_cipher API 
147  */
148 int _gnutls_auth_cipher_init(auth_cipher_hd_st * handle,
149                              const cipher_entry_st * e,
150                              const gnutls_datum_t * cipher_key,
151                              const gnutls_datum_t * iv,
152                              const mac_entry_st * me,
153                              const gnutls_datum_t * mac_key,
154                              int ssl_hmac, int enc)
155 {
156         int ret;
157
158         if (unlikely(e == NULL))
159                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
160
161         FAIL_IF_LIB_ERROR;
162
163         memset(handle, 0, sizeof(*handle));
164
165         if (e->id != GNUTLS_CIPHER_NULL) {
166                 handle->non_null = 1;
167                 ret =
168                     _gnutls_cipher_init(&handle->cipher, e, cipher_key, iv,
169                                         enc);
170                 if (ret < 0)
171                         return gnutls_assert_val(ret);
172         } else
173                 handle->non_null = 0;
174
175         if (me->id != GNUTLS_MAC_AEAD) {
176                 handle->is_mac = 1;
177                 handle->ssl_hmac = ssl_hmac;
178
179                 if (ssl_hmac)
180                         ret =
181                             _gnutls_mac_init_ssl3(&handle->mac.dig, me,
182                                                   mac_key->data,
183                                                   mac_key->size);
184                 else
185                         ret =
186                             _gnutls_mac_init(&handle->mac.mac, me,
187                                              mac_key->data, mac_key->size);
188                 if (ret < 0) {
189                         gnutls_assert();
190                         goto cleanup;
191                 }
192
193                 handle->tag_size = _gnutls_mac_get_algo_len(me);
194         } else if (_gnutls_cipher_algo_is_aead(e)) {
195                 handle->tag_size = _gnutls_cipher_get_tag_size(e);
196         } else {
197                 gnutls_assert();
198                 ret = GNUTLS_E_INVALID_REQUEST;
199                 goto cleanup;
200         }
201
202         return 0;
203       cleanup:
204         if (handle->non_null != 0)
205                 _gnutls_cipher_deinit(&handle->cipher);
206         return ret;
207
208 }
209
210 int _gnutls_auth_cipher_add_auth(auth_cipher_hd_st * handle,
211                                  const void *text, int textlen)
212 {
213         if (handle->is_mac) {
214                 if (handle->ssl_hmac)
215                         return _gnutls_hash(&handle->mac.dig, text,
216                                             textlen);
217                 else
218                         return _gnutls_mac(&handle->mac.mac, text,
219                                            textlen);
220         } else if (_gnutls_cipher_is_aead(&handle->cipher))
221                 return _gnutls_cipher_auth(&handle->cipher, text, textlen);
222         else
223                 return 0;
224 }
225
226 /* The caller must make sure that textlen+pad_size+tag_size is divided by the block size of the cipher */
227 int _gnutls_auth_cipher_encrypt2_tag(auth_cipher_hd_st * handle,
228                                      const uint8_t * text, int textlen,
229                                      void *_ciphertext, int ciphertextlen,
230                                      int pad_size)
231 {
232         int ret;
233         uint8_t *ciphertext = _ciphertext;
234         unsigned blocksize =
235             _gnutls_cipher_get_block_size(handle->cipher.e);
236         unsigned l;
237
238         if (handle->is_mac) {
239                 if (handle->ssl_hmac)
240                         ret =
241                             _gnutls_hash(&handle->mac.dig, text, textlen);
242                 else
243                         ret = _gnutls_mac(&handle->mac.mac, text, textlen);
244                 if (unlikely(ret < 0))
245                         return gnutls_assert_val(ret);
246
247                 if (unlikely(textlen + pad_size + handle->tag_size) >
248                     ciphertextlen)
249                         return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
250
251                 if (handle->non_null != 0) {
252                         l = (textlen / blocksize) * blocksize;
253                         if (l > 0) {
254                                 ret =
255                                 _gnutls_cipher_encrypt2(&handle->cipher, text,
256                                                     l, ciphertext,
257                                                     ciphertextlen);
258                                 if (ret < 0)
259                                         return gnutls_assert_val(ret);
260
261                                 textlen -= l;
262                                 text += l;
263                                 ciphertext += l;
264                                 ciphertextlen -= l;
265                         }
266
267                         if (ciphertext != text && textlen > 0)
268                                 memcpy(ciphertext, text, textlen);
269
270                         ret =
271                             _gnutls_auth_cipher_tag(handle,
272                                                     ciphertext + textlen,
273                                                     handle->tag_size);
274                         if (ret < 0)
275                                 return gnutls_assert_val(ret);
276                         textlen += handle->tag_size;
277
278                         /* TLS 1.0 style padding */
279                         if (pad_size > 0) {
280                                 memset(ciphertext + textlen, pad_size - 1,
281                                        pad_size);
282                                 textlen += pad_size;
283                         }
284
285                         ret =
286                             _gnutls_cipher_encrypt2(&handle->cipher,
287                                                     ciphertext, textlen,
288                                                     ciphertext,
289                                                     ciphertextlen);
290                         if (ret < 0)
291                                 return gnutls_assert_val(ret);
292                 } else {        /* null cipher */
293
294                         if (text != ciphertext)
295                                 memcpy(ciphertext, text, textlen);
296
297                         ret =
298                             _gnutls_auth_cipher_tag(handle,
299                                                     ciphertext + textlen,
300                                                     handle->tag_size);
301                         if (ret < 0)
302                                 return gnutls_assert_val(ret);
303                 }
304         } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
305                 ret =
306                     _gnutls_cipher_encrypt2(&handle->cipher, text, textlen,
307                                             ciphertext, ciphertextlen);
308                 if (unlikely(ret < 0))
309                         return gnutls_assert_val(ret);
310
311                 ret =
312                     _gnutls_auth_cipher_tag(handle, ciphertext + textlen,
313                                             handle->tag_size);
314                 if (unlikely(ret < 0))
315                         return gnutls_assert_val(ret);
316         } else if (handle->non_null == 0 && text != ciphertext)
317                 memcpy(ciphertext, text, textlen);
318
319         return 0;
320 }
321
322 int _gnutls_auth_cipher_decrypt2(auth_cipher_hd_st * handle,
323                                  const void *ciphertext, int ciphertextlen,
324                                  void *text, int textlen)
325 {
326         int ret;
327
328         if (unlikely(ciphertextlen > textlen))
329                 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
330
331         if (handle->non_null != 0) {
332                 ret =
333                     _gnutls_cipher_decrypt2(&handle->cipher, ciphertext,
334                                             ciphertextlen, text, textlen);
335                 if (ret < 0)
336                         return gnutls_assert_val(ret);
337         } else if (handle->non_null == 0 && text != ciphertext)
338                 memcpy(text, ciphertext, ciphertextlen);
339
340         if (handle->is_mac) {
341                 /* The MAC is not to be hashed */
342                 ciphertextlen -= handle->tag_size;
343
344                 if (handle->ssl_hmac)
345                         return _gnutls_hash(&handle->mac.dig, text,
346                                             ciphertextlen);
347                 else
348                         return _gnutls_mac(&handle->mac.mac, text,
349                                            ciphertextlen);
350         }
351
352         return 0;
353 }
354
355 int _gnutls_auth_cipher_tag(auth_cipher_hd_st * handle, void *tag,
356                             int tag_size)
357 {
358         int ret;
359
360         if (handle->is_mac) {
361                 if (handle->ssl_hmac) {
362                         ret =
363                             _gnutls_mac_output_ssl3(&handle->mac.dig, tag);
364                         if (ret < 0)
365                                 return gnutls_assert_val(ret);
366                 } else {
367                         _gnutls_mac_output(&handle->mac.mac, tag);
368                 }
369         } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
370                 _gnutls_cipher_tag(&handle->cipher, tag, tag_size);
371         } else
372                 memset(tag, 0, tag_size);
373
374         return 0;
375 }
376
377 void _gnutls_auth_cipher_deinit(auth_cipher_hd_st * handle)
378 {
379         if (handle->is_mac) {
380                 if (handle->ssl_hmac)   /* failure here doesn't matter */
381                         _gnutls_mac_deinit_ssl3(&handle->mac.dig, NULL);
382                 else
383                         _gnutls_mac_deinit(&handle->mac.mac, NULL);
384         }
385         if (handle->non_null != 0)
386                 _gnutls_cipher_deinit(&handle->cipher);
387 }