Coverage Report

Created: 2026-08-31 07:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/util/random.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
#ifdef USE_URANDOM
46
47
#include <fcntl.h>
48
#include <sys/stat.h>
49
#include <unistd.h>
50
51
#define DEV_RANDOM "/dev/urandom"
52
53
#endif
54
55
/*
56
 * generate a number of random bytes, either using libapr or urandom (no per-request logging)
57
 */
58
28.5k
static apr_byte_t _oidc_util_rand(unsigned char *buf, apr_size_t length) {
59
28.5k
  apr_byte_t rv = FALSE;
60
61
28.5k
#ifndef USE_URANDOM
62
63
28.5k
  rv = (apr_generate_random_bytes(buf, length) == APR_SUCCESS);
64
65
#else
66
67
  int fd = -1;
68
69
  do {
70
    apr_ssize_t rc;
71
72
    if (fd == -1) {
73
      fd = open(DEV_RANDOM, O_RDONLY);
74
      if (fd == -1)
75
        return FALSE;
76
    }
77
78
    do {
79
      rc = read(fd, buf, length);
80
    } while (rc == -1 && errno == EINTR);
81
82
    if (rc < 0) {
83
      int errnum = errno;
84
      close(fd);
85
      return FALSE;
86
    } else if (rc == 0) {
87
      close(fd);
88
      fd = -1; /* force open() again */
89
    } else {
90
      buf += rc;
91
      length -= rc;
92
    }
93
  } while (length > 0);
94
95
  close(fd);
96
97
  rv = TRUE;
98
99
#endif
100
101
28.5k
  return rv;
102
28.5k
}
103
104
/*
105
 * generate a number of random bytes, either using libapr or urandom
106
 */
107
28.5k
static apr_byte_t _oidc_util_rand_bytes(request_rec *r, unsigned char *buf, apr_size_t len) {
108
28.5k
  apr_byte_t rv = TRUE;
109
28.5k
#ifndef USE_URANDOM
110
28.5k
  const char *gen = "apr";
111
#else
112
  const char *gen = DEV_RANDOM;
113
#endif
114
28.5k
  if (r)
115
28.5k
    oidc_debug(r, "use [%s] for generating %" APR_SIZE_T_FMT " random bytes", gen, len);
116
28.5k
  rv = _oidc_util_rand(buf, len);
117
28.5k
  if (r)
118
28.5k
    oidc_debug(r, "return: %d", rv);
119
28.5k
  return rv;
120
28.5k
}
121
122
/*
123
 * generate a random integer value in the specified modulo range
124
 */
125
0
unsigned int oidc_util_rand_int(unsigned int mod) {
126
0
  unsigned int v = 0;
127
0
  unsigned int reject;
128
129
0
  if (mod == 0)
130
0
    return 0;
131
  /* reject the short tail [0, 2^N mod `mod`) so v % mod is uniformly distributed */
132
0
  reject = (0u - mod) % mod;
133
0
  do {
134
0
    if (_oidc_util_rand((unsigned char *)&v, sizeof(v)) != TRUE)
135
0
      return 0;
136
0
  } while (v < reject);
137
0
  return v % mod;
138
0
}
139
140
/*
141
 * generate a random string of base64url encoded characters, representing len bytes
142
 */
143
9.09k
apr_byte_t oidc_util_rand_str(request_rec *r, char **str, int len) {
144
9.09k
  unsigned char *bytes = apr_pcalloc(r->pool, len);
145
9.09k
  if (_oidc_util_rand_bytes(r, bytes, len) != TRUE) {
146
0
    oidc_error(r, "_oidc_util_rand_bytes returned an error");
147
0
    return FALSE;
148
0
  }
149
9.09k
  if (oidc_util_base64url_encode(r, str, (const char *)bytes, len, OIDC_BASE64URL_PADDING_STRIP) <= 0) {
150
0
    oidc_error(r, "oidc_base64url_encode returned an error");
151
0
    return FALSE;
152
0
  }
153
9.09k
  return TRUE;
154
9.09k
}
155
156
/*
157
 * generate a random string of (lowercase) hexadecimal characters, representing len bytes
158
 */
159
19.4k
char *oidc_util_rand_hex_str(request_rec *r, apr_pool_t *pool, int len) {
160
19.4k
  unsigned char *bytes = apr_pcalloc(pool, len);
161
19.4k
  if (_oidc_util_rand_bytes(r, bytes, len) != TRUE) {
162
0
    if (r)
163
0
      oidc_error(r, "_oidc_util_rand_bytes returned an error");
164
0
    return NULL;
165
0
  }
166
19.4k
  return oidc_util_hex_encode(pool, bytes, len);
167
19.4k
}