summaryrefslogtreecommitdiff
path: root/server/util.c
diff options
context:
space:
mode:
authorJacob Champion <jchampion@apache.org>2017-06-20 23:55:20 +0000
committerJacob Champion <jchampion@apache.org>2017-06-20 23:55:20 +0000
commite0852fd12e2ac4afc7540eb78840c4a11cfa2e29 (patch)
tree4422e5f621b33d4a525ce9307ad855f535482623 /server/util.c
parent78a4c3c46e741e1eb64899e6ee9fb913318791e1 (diff)
downloadhttpd-e0852fd12e2ac4afc7540eb78840c4a11cfa2e29.tar.gz
util.c: add a strict Base64 decoding function
ap_pbase64decode_strict() adds to the functionality of ap_pbase64decode() in two ways: - the length of the decoded buffer is returned, allowing embedded NULLs to be retained by the caller - the input string is strictly checked for Base64 validity, including correct zero-padding at the end of the string (This was originally added to the httpdunit feature/backport branch in r1796208, then reverted in r1799376, since it's currently intended for trunk only.) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1799380 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'server/util.c')
-rw-r--r--server/util.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/server/util.c b/server/util.c
index 3c001511be..5d1df08ae3 100644
--- a/server/util.c
+++ b/server/util.c
@@ -2386,6 +2386,76 @@ AP_DECLARE(char *) ap_pbase64decode(apr_pool_t *p, const char *bufcoded)
return decoded;
}
+/* a stringent version of ap_pbase64decode() */
+AP_DECLARE(apr_status_t) ap_pbase64decode_strict(apr_pool_t *p,
+ const char *encoded,
+ char **decoded,
+ apr_size_t *len)
+{
+ apr_size_t end_index;
+ int last_group_len;
+ const char *end;
+
+ /* Sanity check.
+ * TODO: this would be a lot more efficient if we had access to the lookup
+ * table used by APR. If that gets pulled in at any point, make use of it.
+ */
+ end_index = strspn(encoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/");
+
+ last_group_len = end_index % 4;
+ end = encoded + end_index;
+
+ /* The only non-alphabet character allowed is the padding character '=' at
+ * the end of the string. There are two allowable padding cases for the last
+ * group of four: "xY==" or "xyZ=". We require the final (non-padding)
+ * character to have been zero-padded during encoding, which limits the
+ * character choices.
+ */
+ if (last_group_len == 1) {
+ /* This isn't ever valid. */
+ return APR_EINVAL;
+ }
+ else if (last_group_len == 2) {
+ /* ...xY== */
+ if (*end != '=' || end[1] != '=') {
+ return APR_EINVAL;
+ }
+ else if (!ap_strchr("AQgw", end[-1])) {
+ /* Correctly zero-padded input data will result in a final character
+ * that is one of the four above. */
+ return APR_EINVAL;
+ }
+
+ end += 2;
+ }
+ else if (last_group_len == 3) {
+ /* ...xyZ= */
+ if (*end != '=') {
+ return APR_EINVAL;
+ }
+ else if (!ap_strchr("AEIMQUYcgkosw048", end[-1])) {
+ /* Correctly zero-padded input data will result in a final character
+ * that is one of the sixteen above. */
+ return APR_EINVAL;
+ }
+
+ end++;
+ }
+
+ /* At this point, if the encoded buffer is correct, we should be at the end
+ * of the string. */
+ if (*end) {
+ return APR_EINVAL;
+ }
+
+ *decoded = apr_palloc(p, apr_base64_decode_len(encoded));
+ *len = apr_base64_decode(*decoded, encoded);
+
+ return APR_SUCCESS;
+}
+
AP_DECLARE(char *) ap_pbase64encode(apr_pool_t *p, char *string)
{
char *encoded;