Coverage Report

Created: 2025-09-27 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/deps/base64.c
Line
Count
Source
1
/*
2
 * Base64 encoding/decoding (RFC1341)
3
 * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
4
 * Copyright (c) 2025, Julius Pfrommer (Fraunhofer IOSB)
5
 *
6
 * This software may be distributed under the terms of the BSD license.
7
 * See README for more details.
8
 */
9
10
#include "base64.h"
11
#include <open62541/types.h>
12
13
static const unsigned char base64_table[65] =
14
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
15
16
unsigned char *
17
14.0k
UA_base64(const unsigned char *src, size_t len, size_t *out_len) {
18
14.0k
    if(len == 0) {
19
0
        *out_len = 0;
20
0
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
21
0
    }
22
23
14.0k
  size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */
24
14.0k
  if(olen < len)
25
0
    return NULL; /* integer overflow */
26
27
14.0k
  unsigned char *out = (unsigned char*)UA_malloc(olen);
28
14.0k
  if(!out)
29
0
    return NULL;
30
31
14.0k
    *out_len = UA_base64_buf(src, len, out);
32
14.0k
    return out;
33
14.0k
}
34
35
size_t
36
16.1k
UA_base64_buf(const unsigned char *src, size_t len, unsigned char *out) {
37
16.1k
  const unsigned char *end = src + len;
38
16.1k
  const unsigned char *in = src;
39
16.1k
  unsigned char *pos = out;
40
8.11M
  while(end - in >= 3) {
41
8.09M
    *pos++ = base64_table[in[0] >> 2];
42
8.09M
    *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
43
8.09M
    *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
44
8.09M
    *pos++ = base64_table[in[2] & 0x3f];
45
8.09M
    in += 3;
46
8.09M
  }
47
48
16.1k
  if(end - in) {
49
11.3k
    *pos++ = base64_table[in[0] >> 2];
50
11.3k
    if(end - in == 1) {
51
7.33k
      *pos++ = base64_table[(in[0] & 0x03) << 4];
52
7.33k
      *pos++ = '=';
53
7.33k
    } else {
54
4.00k
      *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
55
4.00k
      *pos++ = base64_table[(in[1] & 0x0f) << 2];
56
4.00k
    }
57
11.3k
    *pos++ = '=';
58
11.3k
  }
59
60
16.1k
    return (size_t)(pos - out);
61
16.1k
}
62
63
static unsigned char dtable[128] = {
64
  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80,
65
  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
66
  0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 62  , 0x80, 62  , 0x80, 63  ,
67
  52  , 53  , 54  , 55  , 56  , 57  , 58  , 59  , 60  , 61  , 0x80, 0x80, 0x80, 0   , 0x80, 0x80,
68
  0x80, 0   , 1   , 2   , 3   , 4   , 5   , 6   , 7   , 8   , 9   , 10  , 11  , 12  , 13  , 14  ,
69
  15  , 16  , 17  , 18  , 19  , 20  , 21  , 22  , 23  , 24  , 25  , 0x80, 0x80, 0x80, 0x80, 63  ,
70
  0x80, 26  , 27  , 28  , 29  , 30  , 31  , 32  , 33  , 34  , 35  , 36  , 37  , 38  , 39  , 40  ,
71
  41  , 42  , 43  , 44  , 45  , 46  , 47  , 48  , 49  , 50  , 51  , 0x80, 0x80, 0x80, 0x80, 0x80
72
};
73
74
unsigned char *
75
18.9k
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) {
76
    /* Empty base64 results in an empty byte-string */
77
18.9k
    if(len == 0) {
78
2.32k
        *out_len = 0;
79
2.32k
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
80
2.32k
    }
81
82
    /* Allocate the output string. Append four bytes to allow missing padding */
83
16.6k
  size_t olen = (len / 4 * 3) + 4;
84
16.6k
    unsigned char *out = (unsigned char*)UA_malloc(olen);
85
16.6k
  if(!out)
86
11
    return NULL;
87
88
    /* Iterate over the input */
89
16.6k
  size_t pad = 0;
90
16.6k
    unsigned char count = 0;
91
16.6k
    unsigned char block[4];
92
16.6k
    unsigned char *pos = out;
93
134M
  for(size_t i = 0; i < len; i++) {
94
        /* Process character */
95
134M
    unsigned char tmp = dtable[src[i] & 0x7f];
96
134M
        if(tmp == 0x80)
97
129
            goto error;
98
134M
        if(tmp == 0x7f)
99
12.6k
            continue; /* Whitespace is ignored to accomodate RFC 2045, used in
100
                       * XML for xs:base64Binary. */
101
134M
    block[count++] = tmp;
102
103
        /* Allow padding in the middle.
104
         * For example if base64 streams have been concatenated */
105
134M
        if(src[i] == '=')
106
16.6k
            pad++;
107
108
        /* Premature end of input. Fill up the block with padding. */
109
134M
        if(i + 1 == len) {
110
14.8k
            len = (len + 3) & ~0x03U; /* Next multiple of four */
111
27.1k
            for(i++; i < len; i++)
112
12.3k
                pad++;
113
27.3k
            for(; count < 4; count++)
114
12.5k
                block[count] = 0;
115
14.8k
        }
116
117
        /* Write three output characters for four characters of input */
118
134M
    if(count == 4) {
119
33.7M
            if(pad > 2)
120
92
                goto error; /* Invalid padding */
121
33.7M
      *pos++ = (block[0] << 2) | (block[1] >> 4);
122
33.7M
      *pos++ = (block[1] << 4) | (block[2] >> 2);
123
33.7M
      *pos++ = (block[2] << 6) | block[3];
124
33.7M
      count = 0;
125
33.7M
            pos -= pad;
126
33.7M
            pad = 0;
127
33.7M
    }
128
134M
  }
129
130
16.4k
  *out_len = (size_t)(pos - out);
131
16.4k
    if(*out_len == 0) {
132
1.38k
        UA_free(out);
133
1.38k
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
134
1.38k
    }
135
15.0k
    return out;
136
137
221
 error:
138
221
    UA_free(out);
139
    return NULL;
140
16.4k
}