LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - x509_b64.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 189 204 92.6 %
Date: 2020-10-30 04:50:48 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2000-2012 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2017 Red Hat, Inc.
       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 <https://www.gnu.org/licenses/>
      21             :  *
      22             :  */
      23             : 
      24             : /* Functions that relate to base64 encoding and decoding.
      25             :  */
      26             : 
      27             : #include "gnutls_int.h"
      28             : #include "errors.h"
      29             : #include <datum.h>
      30             : #include <x509_b64.h>
      31             : #include <nettle/base64.h>
      32             : 
      33             : #define INCR(what, size, max_len) \
      34             :         do { \
      35             :         what+=size; \
      36             :         if (what > max_len) { \
      37             :                 gnutls_assert(); \
      38             :                 gnutls_free( result->data); result->data = NULL; \
      39             :                 return GNUTLS_E_INTERNAL_ERROR; \
      40             :         } \
      41             :         } while(0)
      42             : 
      43             : /* encodes data and puts the result into result (locally allocated)
      44             :  * The result_size (including the null terminator) is the return value.
      45             :  */
      46             : int
      47       15255 : _gnutls_fbase64_encode(const char *msg, const uint8_t * data,
      48             :                        size_t data_size, gnutls_datum_t * result)
      49             : {
      50       15255 :         int tmp;
      51       15255 :         unsigned int i;
      52       15255 :         uint8_t tmpres[66];
      53       15255 :         uint8_t *ptr;
      54       15255 :         char top[80];
      55       15255 :         char bottom[80];
      56       15255 :         size_t size, max, bytes;
      57       15255 :         int pos, top_len = 0, bottom_len = 0;
      58       15255 :         unsigned raw_encoding = 0;
      59             : 
      60       15255 :         if (msg == NULL || msg[0] == 0)
      61             :                 raw_encoding = 1;
      62             : 
      63       15165 :         if (!raw_encoding) {
      64       15165 :                 if (strlen(msg) > 50) {
      65           0 :                         gnutls_assert();
      66           0 :                         return GNUTLS_E_BASE64_ENCODING_ERROR;
      67             :                 }
      68             : 
      69       15165 :                 _gnutls_str_cpy(top, sizeof(top), "-----BEGIN ");
      70       15165 :                 _gnutls_str_cat(top, sizeof(top), msg);
      71       15165 :                 _gnutls_str_cat(top, sizeof(top), "-----\n");
      72             : 
      73       15165 :                 _gnutls_str_cpy(bottom, sizeof(bottom), "-----END ");
      74       15165 :                 _gnutls_str_cat(bottom, sizeof(bottom), msg);
      75       15165 :                 _gnutls_str_cat(bottom, sizeof(bottom), "-----\n");
      76             : 
      77       15165 :                 top_len = strlen(top);
      78       15165 :                 bottom_len = strlen(bottom);
      79             :         }
      80             : 
      81       15255 :         max = B64FSIZE(top_len + bottom_len, data_size);
      82             : 
      83       15255 :         result->data = gnutls_malloc(max + 1);
      84       15255 :         if (result->data == NULL) {
      85           0 :                 gnutls_assert();
      86           0 :                 return GNUTLS_E_MEMORY_ERROR;
      87             :         }
      88             : 
      89       15255 :         bytes = 0;
      90       15255 :         INCR(bytes, top_len, max);
      91       15255 :         pos = top_len;
      92             : 
      93       15255 :         memcpy(result->data, top, top_len);
      94             : 
      95       77818 :         for (i = 0; i < data_size; i += 48) {
      96       62563 :                 if (data_size - i < 48)
      97       15143 :                         tmp = data_size - i;
      98             :                 else
      99             :                         tmp = 48;
     100             : 
     101       62563 :                 size = BASE64_ENCODE_RAW_LENGTH(tmp);
     102       62563 :                 if (sizeof(tmpres) < size)
     103           0 :                         return gnutls_assert_val(GNUTLS_E_BASE64_ENCODING_ERROR);
     104             : 
     105       62563 :                 base64_encode_raw((void*)tmpres, tmp, &data[i]);
     106             : 
     107       62563 :                 INCR(bytes, size + 1, max);
     108       62563 :                 ptr = &result->data[pos];
     109             : 
     110       62563 :                 memcpy(ptr, tmpres, size);
     111       62563 :                 ptr += size;
     112       62563 :                 pos += size;
     113       62563 :                 if (!raw_encoding) {
     114       61135 :                         *ptr++ = '\n';
     115       61135 :                         pos++;
     116             :                 } else {
     117             :                         bytes--;
     118             :                 }
     119             :         }
     120             : 
     121       15255 :         INCR(bytes, bottom_len, max);
     122             : 
     123       15255 :         memcpy(&result->data[bytes - bottom_len], bottom, bottom_len);
     124       15255 :         result->data[bytes] = 0;
     125       15255 :         result->size = bytes;
     126             : 
     127       15255 :         return max + 1;
     128             : }
     129             : 
     130             : /**
     131             :  * gnutls_pem_base64_encode:
     132             :  * @msg: is a message to be put in the header (may be %NULL)
     133             :  * @data: contain the raw data
     134             :  * @result: the place where base64 data will be copied
     135             :  * @result_size: holds the size of the result
     136             :  *
     137             :  * This function will convert the given data to printable data, using
     138             :  * the base64 encoding. This is the encoding used in PEM messages.
     139             :  *
     140             :  * The output string will be null terminated, although the output size will
     141             :  * not include the terminating null.
     142             :  *
     143             :  * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
     144             :  *   %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
     145             :  *   not long enough, or 0 on success.
     146             :  **/
     147             : int
     148          70 : gnutls_pem_base64_encode(const char *msg, const gnutls_datum_t * data,
     149             :                          char *result, size_t * result_size)
     150             : {
     151          70 :         gnutls_datum_t res;
     152          70 :         int ret;
     153             : 
     154          70 :         ret = _gnutls_fbase64_encode(msg, data->data, data->size, &res);
     155          70 :         if (ret < 0)
     156             :                 return ret;
     157             : 
     158          70 :         if (result == NULL || *result_size < (unsigned) res.size) {
     159          11 :                 gnutls_free(res.data);
     160          11 :                 *result_size = res.size + 1;
     161          11 :                 return GNUTLS_E_SHORT_MEMORY_BUFFER;
     162             :         } else {
     163          59 :                 memcpy(result, res.data, res.size);
     164          59 :                 gnutls_free(res.data);
     165          59 :                 *result_size = res.size;
     166             :         }
     167             : 
     168          59 :         return 0;
     169             : }
     170             : 
     171             : /**
     172             :  * gnutls_pem_base64_encode2:
     173             :  * @header: is a message to be put in the encoded header (may be %NULL)
     174             :  * @data: contains the raw data
     175             :  * @result: will hold the newly allocated encoded data
     176             :  *
     177             :  * This function will convert the given data to printable data, using
     178             :  * the base64 encoding.  This is the encoding used in PEM messages.
     179             :  * This function will allocate the required memory to hold the encoded
     180             :  * data.
     181             :  *
     182             :  * You should use gnutls_free() to free the returned data.
     183             :  *
     184             :  * Note, that prior to GnuTLS 3.4.0 this function was available
     185             :  * under the name gnutls_pem_base64_encode_alloc(). There is
     186             :  * compatibility macro pointing to this function.
     187             :  *
     188             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
     189             :  *   an error code is returned.
     190             :  *
     191             :  * Since: 3.4.0
     192             :  **/
     193             : int
     194       11980 : gnutls_pem_base64_encode2(const char *header,
     195             :                                const gnutls_datum_t * data,
     196             :                                gnutls_datum_t * result)
     197             : {
     198       11980 :         int ret;
     199             : 
     200       11980 :         if (result == NULL)
     201           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     202             : 
     203       11980 :         ret = _gnutls_fbase64_encode(header, data->data, data->size, result);
     204       11980 :         if (ret < 0)
     205           0 :                 return gnutls_assert_val(ret);
     206             : 
     207             :         return 0;
     208             : }
     209             : 
     210             : /* copies data to result but removes newlines and <CR>
     211             :  * returns the size of the data copied.
     212             :  *
     213             :  * It will fail with GNUTLS_E_BASE64_DECODING_ERROR if the
     214             :  * end-result is the empty string.
     215             :  */
     216             : inline static int
     217       19984 : cpydata(const uint8_t * data, int data_size, gnutls_datum_t * result)
     218             : {
     219       19984 :         int i, j;
     220             : 
     221       19984 :         result->data = gnutls_malloc(data_size + 1);
     222       19984 :         if (result->data == NULL)
     223             :                 return GNUTLS_E_MEMORY_ERROR;
     224             : 
     225    21946600 :         for (j = i = 0; i < data_size; i++) {
     226    21930100 :                 if (data[i] == '\n' || data[i] == '\r' || data[i] == ' '
     227    21589800 :                     || data[i] == '\t')
     228      340900 :                         continue;
     229    21589200 :                 else if (data[i] == '-')
     230             :                         break;
     231    21585700 :                 result->data[j] = data[i];
     232    21585700 :                 j++;
     233             :         }
     234             : 
     235       19984 :         result->size = j;
     236       19984 :         result->data[j] = 0;
     237             : 
     238       19984 :         if (j==0) {
     239        1233 :                 gnutls_free(result->data);
     240        1233 :                 return gnutls_assert_val(GNUTLS_E_BASE64_DECODING_ERROR);
     241             :         }
     242             : 
     243             :         return j;
     244             : }
     245             : 
     246             : /* decodes data and puts the result into result (locally allocated).
     247             :  * Note that encodings of zero-length strings are being rejected
     248             :  * with GNUTLS_E_BASE64_DECODING_ERROR.
     249             :  *
     250             :  * The result_size is the return value.
     251             :  */
     252             : int
     253       19985 : _gnutls_base64_decode(const uint8_t * data, size_t data_size,
     254             :                       gnutls_datum_t * result)
     255             : {
     256       19985 :         int ret;
     257       19985 :         size_t size;
     258       19985 :         gnutls_datum_t pdata;
     259       19985 :         struct base64_decode_ctx ctx;
     260             : 
     261       19985 :         if (data_size == 0) {
     262           1 :                 result->data = (unsigned char*)gnutls_strdup("");
     263           1 :                 if (result->data == NULL)
     264           0 :                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     265           1 :                 result->size = 0;
     266           1 :                 return 0;
     267             :         }
     268             : 
     269       19984 :         ret = cpydata(data, data_size, &pdata);
     270       19984 :         if (ret < 0) {
     271        1233 :                 gnutls_assert();
     272        1233 :                 return ret;
     273             :         }
     274             : 
     275       18751 :         base64_decode_init(&ctx);
     276             : 
     277       18751 :         size = BASE64_DECODE_LENGTH(pdata.size);
     278       18751 :         if (size == 0) {
     279           0 :                 ret = gnutls_assert_val(GNUTLS_E_BASE64_DECODING_ERROR);
     280           0 :                 goto cleanup;
     281             :         }
     282             : 
     283       18751 :         result->data = gnutls_malloc(size);
     284       18751 :         if (result->data == NULL) {
     285           0 :                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     286           0 :                 goto cleanup;
     287             :         }
     288             : 
     289       37502 :         ret = base64_decode_update(&ctx, &size, result->data,
     290       18751 :                                    pdata.size, (void*)pdata.data);
     291       18751 :         if (ret == 0 || size == 0) {
     292         645 :                 gnutls_assert();
     293         645 :                 ret = GNUTLS_E_BASE64_DECODING_ERROR;
     294         645 :                 goto fail;
     295             :         }
     296             : 
     297       18106 :         ret = base64_decode_final(&ctx);
     298       18106 :         if (ret != 1) {
     299         490 :                 ret = gnutls_assert_val(GNUTLS_E_BASE64_DECODING_ERROR);
     300         490 :                 goto fail;
     301             :         }
     302             : 
     303       17616 :         result->size = size;
     304             : 
     305       17616 :         ret = size;
     306       17616 :         goto cleanup;
     307             : 
     308        1135 :  fail:
     309        1135 :         gnutls_free(result->data);
     310             : 
     311       18751 :  cleanup:
     312       18751 :         gnutls_free(pdata.data);
     313       18751 :         return ret;
     314             : }
     315             : 
     316             : 
     317             : /* Searches the given string for ONE PEM encoded certificate, and
     318             :  * stores it in the result.
     319             :  *
     320             :  * The result_size (always non-zero) is the return value,
     321             :  * or a negative error code.
     322             :  */
     323             : #define ENDSTR "-----"
     324             : int
     325       20544 : _gnutls_fbase64_decode(const char *header, const uint8_t * data,
     326             :                        size_t data_size, gnutls_datum_t * result)
     327             : {
     328       20544 :         int ret;
     329       20544 :         static const char top[] = "-----BEGIN ";
     330       20544 :         static const char bottom[] = "-----END ";
     331       20544 :         uint8_t *rdata, *kdata;
     332       20544 :         int rdata_size;
     333       20544 :         char pem_header[128];
     334             : 
     335       20544 :         _gnutls_str_cpy(pem_header, sizeof(pem_header), top);
     336       20544 :         if (header != NULL)
     337       20440 :                 _gnutls_str_cat(pem_header, sizeof(pem_header), header);
     338             : 
     339       20544 :         rdata = memmem(data, data_size, pem_header, strlen(pem_header));
     340       20544 :         if (rdata == NULL) {
     341         392 :                 gnutls_assert();
     342         392 :                 _gnutls_hard_log("Could not find '%s'\n", pem_header);
     343         392 :                 return GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR;
     344             :         }
     345             : 
     346       20152 :         data_size -= MEMSUB(rdata, data);
     347             : 
     348       20152 :         if (data_size < 4 + strlen(bottom)) {
     349           2 :                 gnutls_assert();
     350           2 :                 return GNUTLS_E_BASE64_DECODING_ERROR;
     351             :         }
     352             : 
     353       20150 :         kdata =
     354       20150 :             memmem(rdata + 1, data_size - 1, ENDSTR, sizeof(ENDSTR) - 1);
     355             :         /* allow CR as well.
     356             :          */
     357       20150 :         if (kdata == NULL) {
     358           5 :                 gnutls_assert();
     359           5 :                 _gnutls_hard_log("Could not find '%s'\n", ENDSTR);
     360           5 :                 return GNUTLS_E_BASE64_DECODING_ERROR;
     361             :         }
     362       20145 :         data_size -= strlen(ENDSTR);
     363       20145 :         data_size -= MEMSUB(kdata, rdata);
     364             : 
     365       20145 :         rdata = kdata + strlen(ENDSTR);
     366             : 
     367             :         /* position is now after the ---BEGIN--- headers */
     368             : 
     369       20145 :         kdata = memmem(rdata, data_size, bottom, strlen(bottom));
     370       20145 :         if (kdata == NULL) {
     371          24 :                 gnutls_assert();
     372          24 :                 return GNUTLS_E_BASE64_DECODING_ERROR;
     373             :         }
     374             : 
     375             :         /* position of kdata is before the ----END--- footer 
     376             :          */
     377       20121 :         rdata_size = MEMSUB(kdata, rdata);
     378             : 
     379       20121 :         if (rdata_size < 4) {
     380         196 :                 gnutls_assert();
     381         196 :                 return GNUTLS_E_BASE64_DECODING_ERROR;
     382             :         }
     383             : 
     384       19925 :         if ((ret = _gnutls_base64_decode(rdata, rdata_size, result)) < 0) {
     385        2319 :                 gnutls_assert();
     386        2319 :                 return GNUTLS_E_BASE64_DECODING_ERROR;
     387             :         }
     388             : 
     389             :         return ret;
     390             : }
     391             : 
     392             : /**
     393             :  * gnutls_pem_base64_decode:
     394             :  * @header: A null terminated string with the PEM header (eg. CERTIFICATE)
     395             :  * @b64_data: contain the encoded data
     396             :  * @result: the place where decoded data will be copied
     397             :  * @result_size: holds the size of the result
     398             :  *
     399             :  * This function will decode the given encoded data.  If the header
     400             :  * given is non %NULL this function will search for "-----BEGIN header"
     401             :  * and decode only this part.  Otherwise it will decode the first PEM
     402             :  * packet found.
     403             :  *
     404             :  * Returns: On success %GNUTLS_E_SUCCESS (0) is returned,
     405             :  *   %GNUTLS_E_SHORT_MEMORY_BUFFER is returned if the buffer given is
     406             :  *   not long enough, or 0 on success.
     407             :  **/
     408             : int
     409          48 : gnutls_pem_base64_decode(const char *header,
     410             :                          const gnutls_datum_t * b64_data,
     411             :                          unsigned char *result, size_t * result_size)
     412             : {
     413          48 :         gnutls_datum_t res;
     414          48 :         int ret;
     415             : 
     416          48 :         ret =
     417          48 :             _gnutls_fbase64_decode(header, b64_data->data, b64_data->size,
     418             :                                    &res);
     419          48 :         if (ret < 0)
     420          43 :                 return gnutls_assert_val(ret);
     421             : 
     422           5 :         if (result == NULL || *result_size < (unsigned) res.size) {
     423           1 :                 gnutls_free(res.data);
     424           1 :                 *result_size = res.size;
     425           1 :                 return GNUTLS_E_SHORT_MEMORY_BUFFER;
     426             :         } else {
     427           4 :                 memcpy(result, res.data, res.size);
     428           4 :                 gnutls_free(res.data);
     429           4 :                 *result_size = res.size;
     430             :         }
     431             : 
     432           4 :         return 0;
     433             : }
     434             : 
     435             : /**
     436             :  * gnutls_pem_base64_decode2:
     437             :  * @header: The PEM header (eg. CERTIFICATE)
     438             :  * @b64_data: contains the encoded data
     439             :  * @result: the location of decoded data
     440             :  *
     441             :  * This function will decode the given encoded data. The decoded data
     442             :  * will be allocated, and stored into result.  If the header given is
     443             :  * non null this function will search for "-----BEGIN header" and
     444             :  * decode only this part. Otherwise it will decode the first PEM
     445             :  * packet found.
     446             :  *
     447             :  * You should use gnutls_free() to free the returned data.
     448             :  *
     449             :  * Note, that prior to GnuTLS 3.4.0 this function was available
     450             :  * under the name gnutls_pem_base64_decode_alloc(). There is
     451             :  * compatibility macro pointing to this function.
     452             :  *
     453             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
     454             :  *   an error code is returned.
     455             :  *
     456             :  * Since: 3.4.0
     457             :  **/
     458             : int
     459         152 : gnutls_pem_base64_decode2(const char *header,
     460             :                                const gnutls_datum_t * b64_data,
     461             :                                gnutls_datum_t * result)
     462             : {
     463         152 :         int ret;
     464             : 
     465         152 :         if (result == NULL)
     466           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     467             : 
     468         152 :         ret =
     469         152 :             _gnutls_fbase64_decode(header, b64_data->data, b64_data->size,
     470             :                                    result);
     471         152 :         if (ret < 0)
     472          50 :                 return gnutls_assert_val(ret);
     473             : 
     474             :         return 0;
     475             : }
     476             : 
     477             : /**
     478             :  * gnutls_base64_decode2:
     479             :  * @base64: contains the encoded data
     480             :  * @result: the location of decoded data
     481             :  *
     482             :  * This function will decode the given base64 encoded data. The decoded data
     483             :  * will be allocated, and stored into result.
     484             :  *
     485             :  * You should use gnutls_free() to free the returned data.
     486             :  *
     487             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
     488             :  *   an error code is returned.
     489             :  *
     490             :  * Since: 3.6.0
     491             :  **/
     492             : int
     493          57 : gnutls_base64_decode2(const gnutls_datum_t *base64,
     494             :                       gnutls_datum_t *result)
     495             : {
     496          57 :         int ret;
     497             : 
     498          57 :         ret = _gnutls_base64_decode(base64->data, base64->size, result);
     499          57 :         if (ret < 0) {
     500          49 :                 return gnutls_assert_val(ret);
     501             :         }
     502             : 
     503             :         return 0;
     504             : }
     505             : 
     506             : /**
     507             :  * gnutls_base64_encode2:
     508             :  * @data: contains the raw data
     509             :  * @result: will hold the newly allocated encoded data
     510             :  *
     511             :  * This function will convert the given data to printable data, using
     512             :  * the base64 encoding. This function will allocate the required
     513             :  * memory to hold the encoded data.
     514             :  *
     515             :  * You should use gnutls_free() to free the returned data.
     516             :  *
     517             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
     518             :  *   an error code is returned.
     519             :  *
     520             :  * Since: 3.6.0
     521             :  **/
     522             : int
     523          18 : gnutls_base64_encode2(const gnutls_datum_t *data,
     524             :                       gnutls_datum_t *result)
     525             : {
     526          18 :         int ret;
     527             : 
     528          18 :         if (result == NULL)
     529           0 :                 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     530             : 
     531          18 :         ret = _gnutls_fbase64_encode(NULL, data->data, data->size, result);
     532          18 :         if (ret < 0)
     533           0 :                 return gnutls_assert_val(ret);
     534             : 
     535             :         return 0;
     536             : }

Generated by: LCOV version 1.14