/src/open62541/deps/base64.c
Line | Count | Source (jump to first uncovered line) |
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 | 0 | UA_base64(const unsigned char *src, size_t len, size_t *out_len) { |
18 | 0 | if(len == 0) { |
19 | 0 | *out_len = 0; |
20 | 0 | return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; |
21 | 0 | } |
22 | | |
23 | 0 | size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */ |
24 | 0 | if(olen < len) |
25 | 0 | return NULL; /* integer overflow */ |
26 | | |
27 | 0 | unsigned char *out = (unsigned char*)UA_malloc(olen); |
28 | 0 | if(!out) |
29 | 0 | return NULL; |
30 | | |
31 | 0 | *out_len = UA_base64_buf(src, len, out); |
32 | 0 | return out; |
33 | 0 | } |
34 | | |
35 | | size_t |
36 | 0 | UA_base64_buf(const unsigned char *src, size_t len, unsigned char *out) { |
37 | 0 | const unsigned char *end = src + len; |
38 | 0 | const unsigned char *in = src; |
39 | 0 | unsigned char *pos = out; |
40 | 0 | while(end - in >= 3) { |
41 | 0 | *pos++ = base64_table[in[0] >> 2]; |
42 | 0 | *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; |
43 | 0 | *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; |
44 | 0 | *pos++ = base64_table[in[2] & 0x3f]; |
45 | 0 | in += 3; |
46 | 0 | } |
47 | |
|
48 | 0 | if(end - in) { |
49 | 0 | *pos++ = base64_table[in[0] >> 2]; |
50 | 0 | if(end - in == 1) { |
51 | 0 | *pos++ = base64_table[(in[0] & 0x03) << 4]; |
52 | 0 | *pos++ = '='; |
53 | 0 | } else { |
54 | 0 | *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; |
55 | 0 | *pos++ = base64_table[(in[1] & 0x0f) << 2]; |
56 | 0 | } |
57 | 0 | *pos++ = '='; |
58 | 0 | } |
59 | |
|
60 | 0 | return (size_t)(pos - out); |
61 | 0 | } |
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 | 0 | UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { |
76 | | /* Empty base64 results in an empty byte-string */ |
77 | 0 | if(len == 0) { |
78 | 0 | *out_len = 0; |
79 | 0 | return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; |
80 | 0 | } |
81 | | |
82 | | /* Allocate the output string. Append four bytes to allow missing padding */ |
83 | 0 | size_t olen = (len / 4 * 3) + 4; |
84 | 0 | unsigned char *out = (unsigned char*)UA_malloc(olen); |
85 | 0 | if(!out) |
86 | 0 | return NULL; |
87 | | |
88 | | /* Iterate over the input */ |
89 | 0 | size_t pad = 0; |
90 | 0 | unsigned char count = 0; |
91 | 0 | unsigned char block[4]; |
92 | 0 | unsigned char *pos = out; |
93 | 0 | for(size_t i = 0; i < len; i++) { |
94 | | /* Process character */ |
95 | 0 | unsigned char tmp = dtable[src[i] & 0x7f]; |
96 | 0 | if(tmp == 0x80) |
97 | 0 | goto error; |
98 | 0 | if(tmp == 0x7f) |
99 | 0 | continue; /* Whitespace is ignored to accomodate RFC 2045, used in |
100 | | * XML for xs:base64Binary. */ |
101 | 0 | block[count++] = tmp; |
102 | | |
103 | | /* Allow padding in the middle. |
104 | | * For example if base64 streams have been concatenated */ |
105 | 0 | if(src[i] == '=') |
106 | 0 | pad++; |
107 | | |
108 | | /* Premature end of input. Fill up the block with padding. */ |
109 | 0 | if(i + 1 == len) { |
110 | 0 | len = (len + 3) & ~0x03; /* Next multiple of four */ |
111 | 0 | for(i++; i < len; i++) |
112 | 0 | pad++; |
113 | 0 | for(; count < 4; count++) |
114 | 0 | block[count] = 0; |
115 | 0 | } |
116 | | |
117 | | /* Write three output characters for four characters of input */ |
118 | 0 | if(count == 4) { |
119 | 0 | if(pad > 2) |
120 | 0 | goto error; /* Invalid padding */ |
121 | 0 | *pos++ = (block[0] << 2) | (block[1] >> 4); |
122 | 0 | *pos++ = (block[1] << 4) | (block[2] >> 2); |
123 | 0 | *pos++ = (block[2] << 6) | block[3]; |
124 | 0 | count = 0; |
125 | 0 | pos -= pad; |
126 | 0 | pad = 0; |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | 0 | *out_len = (size_t)(pos - out); |
131 | 0 | if(*out_len == 0) { |
132 | 0 | UA_free(out); |
133 | 0 | return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; |
134 | 0 | } |
135 | 0 | return out; |
136 | | |
137 | 0 | error: |
138 | 0 | UA_free(out); |
139 | 0 | return NULL; |
140 | 0 | } |