Coverage Report

Created: 2026-09-03 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/util/base64.c
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
/***************************************************************************
21
 * Copyright (C) 2017-2026 ZmartZone Holding BV
22
 * All rights reserved.
23
 *
24
 * DISCLAIMER OF WARRANTIES:
25
 *
26
 * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
27
 * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING,
28
 * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT,
29
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  NOR ARE THERE ANY
30
 * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE
31
 * USAGE.  FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET
32
 * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE
33
 * WILL BE UNINTERRUPTED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
34
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF
36
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
 *
40
 * @Author: Hans Zandbelt - hans.zandbelt@openidc.com
41
 */
42
43
#include "util/util.h"
44
45
#include <apr_base64.h>
46
/*
47
 * base64url encode a string
48
 */
49
int oidc_util_base64url_encode(request_rec *r, char **dst, const char *src, int src_len,
50
65.3k
             oidc_base64url_padding_t padding) {
51
65.3k
  if ((src == NULL) || (src_len <= 0)) {
52
0
    oidc_error(r, "not encoding anything; src=NULL and/or src_len<1");
53
0
    return -1;
54
0
  }
55
65.3k
  unsigned int enc_len = apr_base64_encode_len(src_len);
56
65.3k
  char *enc = apr_palloc(r->pool, enc_len);
57
65.3k
  apr_base64_encode(enc, src, src_len);
58
65.3k
  unsigned int i = 0;
59
2.93M
  while (enc[i] != '\0') {
60
2.86M
    if (enc[i] == '+')
61
33.6k
      enc[i] = '-';
62
2.86M
    if (enc[i] == '/')
63
47.5k
      enc[i] = '_';
64
2.86M
    if (enc[i] == '=')
65
65.7k
      enc[i] = ',';
66
2.86M
    i++;
67
2.86M
  }
68
65.3k
  if (padding == OIDC_BASE64URL_PADDING_STRIP) {
69
    /* the loop above already walked to the terminator, so `i` is the encoded length; drop the
70
     * padding from it (base64 emits at most two '=', rewritten to ',' above). Deriving the
71
     * index from the walk rather than from apr_base64_encode_len() also keeps it provably in
72
     * bounds - the length function is opaque to gcc -fanalyzer, which flagged the previous
73
     * enc_len arithmetic as a possible over-read. */
74
131k
    while ((i > 0) && (enc[i - 1] == ','))
75
65.7k
      i--;
76
65.3k
    enc[i] = '\0';
77
65.3k
    enc_len = i;
78
65.3k
  }
79
65.3k
  *dst = enc;
80
65.3k
  return enc_len;
81
65.3k
}
82
83
/*
84
 * parse a base64 encoded binary value from the provided string;
85
 * returns NULL on success and writes the decoded bytes and length into
86
 * *output / *output_len, or returns an error string on failure
87
 */
88
91.9k
char *oidc_util_base64_decode(apr_pool_t *pool, const char *input, char **output, int *output_len) {
89
91.9k
  if ((input == NULL) || (output == NULL) || (output_len == NULL))
90
0
    return apr_psprintf(pool, "base64-decoding failed: invalid parameters");
91
92
91.9k
  *output = apr_pcalloc(pool, apr_base64_decode_len(input));
93
91.9k
  *output_len = apr_base64_decode(*output, input);
94
95
91.9k
  if (*output_len <= 0)
96
1.03k
    return apr_psprintf(pool, "base64-decoding of \"%s\" failed", input);
97
98
90.9k
  return NULL;
99
91.9k
}
100
101
/* Base64url decode length or a non-positive error. Callers must use a signed result type. */
102
93.6k
int oidc_util_base64url_decode(apr_pool_t *pool, char **dst, const char *src) {
103
93.6k
  if (src == NULL) {
104
0
    return -1;
105
0
  }
106
93.6k
  char *dec = apr_pstrdup(pool, src);
107
93.6k
  int i = 0;
108
67.3M
  while (dec[i] != '\0') {
109
67.2M
    if (dec[i] == '-')
110
15.1k
      dec[i] = '+';
111
67.2M
    if (dec[i] == '_')
112
32.6k
      dec[i] = '/';
113
67.2M
    if (dec[i] == ',')
114
2.96M
      dec[i] = '=';
115
67.2M
    i++;
116
67.2M
  }
117
93.6k
  switch (_oidc_strlen(dec) % 4) {
118
23.3k
  case 0:
119
23.3k
    break;
120
17.3k
  case 2:
121
17.3k
    dec = apr_pstrcat(pool, dec, "==", NULL);
122
17.3k
    break;
123
51.2k
  case 3:
124
51.2k
    dec = apr_pstrcat(pool, dec, "=", NULL);
125
51.2k
    break;
126
1.73k
  default:
127
1.73k
    return 0;
128
93.6k
  }
129
130
91.9k
  int dlen = -1;
131
91.9k
  oidc_util_base64_decode(pool, dec, dst, &dlen);
132
91.9k
  return dlen;
133
93.6k
}