diff options
author | Idan Moral <idan22moral@gmail.com> | 2021-07-19 00:45:19 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-19 00:45:19 (GMT) |
commit | 35b98e38b6edd63153fc8e092f94cb20725dacc1 (patch) | |
tree | 0075d1bd3b9f195c5bd60553f9adcb5ef72a6fa1 /Modules/binascii.c | |
parent | b494685b2548489efcc66993cc6c13b027ce3b26 (diff) | |
download | cpython-35b98e38b6edd63153fc8e092f94cb20725dacc1.zip cpython-35b98e38b6edd63153fc8e092f94cb20725dacc1.tar.gz cpython-35b98e38b6edd63153fc8e092f94cb20725dacc1.tar.bz2 |
bpo-43086: Add handling for out-of-spec data in a2b_base64 (GH-24402)
binascii.a2b_base64 gains a strict_mode= parameter. When enabled it will raise an
error on input that deviates from the base64 spec in any way. The default remains
False for backward compatibility.
Code reviews and minor tweaks by: Gregory P. Smith <greg@krypto.org> [Google]
Diffstat (limited to 'Modules/binascii.c')
-rw-r--r-- | Modules/binascii.c | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/Modules/binascii.c b/Modules/binascii.c index 59e4b0a..50f25b4 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -433,18 +433,26 @@ binascii.a2b_base64 data: ascii_buffer / + * + strict_mode: bool(accept={int}) = False Decode a line of base64 data. + + strict_mode + When set to True, bytes that are not part of the base64 standard are not allowed. + The same applies to excess data after padding (= / ==). [clinic start generated code]*/ static PyObject * -binascii_a2b_base64_impl(PyObject *module, Py_buffer *data) -/*[clinic end generated code: output=0628223f19fd3f9b input=5872acf6e1cac243]*/ +binascii_a2b_base64_impl(PyObject *module, Py_buffer *data, int strict_mode) +/*[clinic end generated code: output=5409557788d4f975 input=3a30c4e3528317c6]*/ { assert(data->len >= 0); const unsigned char *ascii_data = data->buf; size_t ascii_len = data->len; + binascii_state *state = NULL; + char padding_started = 0; /* Allocate the buffer */ Py_ssize_t bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ @@ -455,6 +463,15 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data) return NULL; unsigned char *bin_data_start = bin_data; + if (strict_mode && ascii_len > 0 && ascii_data[0] == '=') { + malformed_padding: + state = get_binascii_state(module); + if (state) { + PyErr_SetString(state->Error, "Leading padding not allowed"); + } + goto error_end; + } + int quad_pos = 0; unsigned char leftchar = 0; int pads = 0; @@ -465,11 +482,21 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data) ** the invalid ones. */ if (this_ch == BASE64_PAD) { + padding_started = 1; + if (quad_pos >= 2 && quad_pos + ++pads >= 4) { - /* A pad sequence means no more input. - ** We've already interpreted the data - ** from the quad at this point. + /* A pad sequence means we should not parse more input. + ** We've already interpreted the data from the quad at this point. + ** in strict mode, an error should raise if there's excess data after the padding. */ + if (strict_mode && i + 1 < ascii_len) { + state = get_binascii_state(module); + if (state) { + PyErr_SetString(state->Error, "Excess data after padding"); + } + goto error_end; + } + goto done; } continue; @@ -477,8 +504,20 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data) this_ch = table_a2b_base64[this_ch]; if (this_ch >= 64) { + if (strict_mode) { + state = get_binascii_state(module); + if (state) { + PyErr_SetString(state->Error, "Only base64 data is allowed"); + } + goto error_end; + } continue; } + + // Characters that are not '=', in the middle of the padding, are not allowed + if (strict_mode && padding_started) { + goto malformed_padding; + } pads = 0; switch (quad_pos) { @@ -505,7 +544,7 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data) } if (quad_pos != 0) { - binascii_state *state = get_binascii_state(module); + state = get_binascii_state(module); if (state == NULL) { /* error already set, from get_binascii_state */ } else if (quad_pos == 1) { @@ -522,6 +561,7 @@ binascii_a2b_base64_impl(PyObject *module, Py_buffer *data) } else { PyErr_SetString(state->Error, "Incorrect padding"); } + error_end: _PyBytesWriter_Dealloc(&writer); return NULL; } |