Coverage Report

Created: 2026-08-14 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/core/ogs-uuid.c
Line
Count
Source
1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
 * contributor license agreements.  See the NOTICE file distributed with
3
 * this work for additional information regarding copyright ownership.
4
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * (the "License"); you may not use this file except in compliance with
6
 * the License.  You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
/*
18
 * Copyright (C) 2019-2020 by Sukchan Lee <acetcom@gmail.com>
19
 *
20
 * This file is part of Open5GS.
21
 *
22
 * Licensed under the Apache License, Version 2.0 (the "License");
23
 * you may not use this file except in compliance with the License.
24
 * You may obtain a copy of the License at
25
 *
26
 *   http://www.apache.org/licenses/LICENSE-2.0
27
 *
28
 * Unless required by applicable law or agreed to in writing, software
29
 * distributed under the License is distributed on an "AS IS" BASIS,
30
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31
 * See the License for the specific language governing permissions and
32
 * limitations under the License.
33
 */
34
35
#include "core-config-private.h"
36
37
#if HAVE_CTYPE_H
38
#include <ctype.h>
39
#endif
40
41
#include "ogs-core.h"
42
43
0
#define NODE_LENGTH 6
44
45
static int uuid_state_seqnum;
46
static unsigned char uuid_state_node[NODE_LENGTH] = { 0 };
47
48
static void get_random_info(unsigned char node[NODE_LENGTH])
49
0
{
50
0
    ogs_random(node, NODE_LENGTH);
51
0
}
52
53
/* This implementation generates a random node ID instead of a
54
   system-dependent call to get IEEE node ID. This is also more secure:
55
   we aren't passing out our MAC address. */
56
static void get_pseudo_node_identifier(unsigned char *node)
57
0
{
58
0
    get_random_info(node);
59
0
    node[0] |= 0x01; /* this designates a random multicast node ID */
60
0
}
61
62
/* true_random -- generate a crypto-quality random number. */
63
static int true_random(void)
64
0
{
65
0
    unsigned char buf[2];
66
67
0
    ogs_random(buf, 2);
68
0
    return (buf[0] << 8) | buf[1];
69
0
}
70
71
static void init_state(void)
72
0
{
73
0
    uuid_state_seqnum = true_random();
74
0
    get_pseudo_node_identifier(uuid_state_node);
75
0
}
76
77
static void get_system_time(uint64_t *uuid_time)
78
0
{
79
0
    struct timeval tv;
80
81
    /* ### fix this call to be more portable? */
82
0
    ogs_gettimeofday(&tv);
83
0
    *uuid_time = ogs_time_from_sec(tv.tv_sec) + tv.tv_usec;
84
85
    /* Offset between UUID formatted times and Unix formatted times.
86
       UUID UTC base time is October 15, 1582.
87
       Unix base time is January 1, 1970.      */
88
0
    *uuid_time = (*uuid_time * 10) + 0x01B21DD213814000;
89
0
}
90
91
static void get_current_time(uint64_t *timestamp)
92
0
{
93
    /* ### this needs to be made thread-safe! */
94
95
0
    uint64_t time_now;
96
0
    static uint64_t time_last = 0;
97
0
    static uint64_t fudge = 0;
98
99
0
    get_system_time(&time_now);
100
        
101
    /* if clock reading changed since last UUID generated... */
102
0
    if (time_last != time_now) {
103
        /* The clock reading has changed since the last UUID was generated.
104
           Reset the fudge factor. if we are generating them too fast, then
105
           the fudge may need to be reset to something greater than zero. */
106
0
        if (time_last + fudge > time_now)
107
0
            fudge = time_last + fudge - time_now + 1;
108
0
        else
109
0
            fudge = 0;
110
0
        time_last = time_now;
111
0
    }
112
0
    else {
113
        /* We generated two really fast. Bump the fudge factor. */
114
0
        ++fudge;
115
0
    }
116
117
0
    *timestamp = time_now + fudge;
118
0
}
119
120
void ogs_uuid_get(ogs_uuid_t *uuid)
121
0
{
122
0
    uint64_t timestamp;
123
0
    unsigned char *d = NULL;
124
0
    int version = 4;
125
126
0
    ogs_assert(uuid);
127
0
    d = uuid->data;
128
129
0
    if (!uuid_state_node[0])
130
0
        init_state();
131
132
0
    get_current_time(&timestamp);
133
134
    /* time_low, uint32 */
135
0
    d[3] = (unsigned char)timestamp;
136
0
    d[2] = (unsigned char)(timestamp >> 8);
137
0
    d[1] = (unsigned char)(timestamp >> 16);
138
0
    d[0] = (unsigned char)(timestamp >> 24);
139
140
    /* time_mid, uint16 */
141
0
    d[5] = (unsigned char)(timestamp >> 32);
142
0
    d[4] = (unsigned char)(timestamp >> 40);
143
144
    /* Set the four most significant bits (bits 12 through 15) of the
145
     * time_hi_and_version field to the 4-bit version number from
146
     * Section 4.1.3. */
147
0
    d[7] = (unsigned char)(timestamp >> 48);
148
0
    d[6] = (unsigned char)(((timestamp >> 56) & 0x0F) | (version << 4));
149
150
    /* Set the two most significant bits (bits 6 and 7) of the
151
     * clock_seq_hi_and_reserved to zero and one, respectively. */
152
0
    d[8] = (unsigned char)(((uuid_state_seqnum >> 8) & 0x3F) | 0x80);
153
154
    /* clock_seq_low, uint8 */
155
0
    d[9] = (unsigned char)uuid_state_seqnum;
156
157
    /* node, byte[6] */
158
0
    memcpy(&d[10], uuid_state_node, NODE_LENGTH);
159
0
}
160
161
void ogs_uuid_format(char *buffer, const ogs_uuid_t *uuid)
162
0
{
163
0
    const unsigned char *d = uuid->data;
164
165
0
    ogs_snprintf(buffer, OGS_UUID_FORMATTED_LENGTH + 1,
166
0
                    "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
167
0
                    "%02x%02x%02x%02x%02x%02x",
168
0
                    d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
169
0
                    d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
170
0
}
171
172
/* convert a pair of hex digits to an integer value [0,255] */
173
#if 'A' == 65
174
static unsigned char parse_hexpair(const char *s)
175
0
{
176
0
    int result;
177
0
    int temp;
178
179
0
    result = s[0] - '0';
180
0
    if (result > 48)
181
0
        result = (result - 39) << 4;
182
0
    else if (result > 16)
183
0
        result = (result - 7) << 4;
184
0
    else
185
0
        result = result << 4;
186
187
0
    temp = s[1] - '0';
188
0
    if (temp > 48)
189
0
        result |= temp - 39;
190
0
    else if (temp > 16)
191
0
        result |= temp - 7;
192
0
    else
193
0
        result |= temp;
194
195
0
    return (unsigned char)result;
196
0
}
197
#else
198
static unsigned char parse_hexpair(const char *s)
199
{
200
    int result;
201
202
    if (isdigit(*s)) {
203
        result = (*s - '0') << 4;
204
    }
205
    else {
206
        if (isupper(*s)) {
207
            result = (*s - 'A' + 10) << 4;
208
        }
209
        else {
210
            result = (*s - 'a' + 10) << 4;
211
        }
212
    }
213
214
    ++s;
215
    if (isdigit(*s)) {
216
        result |= (*s - '0');
217
    }
218
    else {
219
        if (isupper(*s)) {
220
            result |= (*s - 'A' + 10);
221
        }
222
        else {
223
            result |= (*s - 'a' + 10);
224
        }
225
    }
226
227
    return (unsigned char)result;
228
}
229
#endif
230
231
int ogs_uuid_parse(ogs_uuid_t *uuid, const char *uuid_str)
232
0
{
233
0
    int i;
234
0
    unsigned char *d = uuid->data;
235
236
0
    for (i = 0; i < 36; ++i) {
237
0
        char c = uuid_str[i];
238
0
        if (!isxdigit(c) &&
239
0
            !(c == '-' && (i == 8 || i == 13 || i == 18 || i == 23)))
240
            /* ### need a better value */
241
0
            return OGS_ERROR;
242
0
    }
243
0
    if (uuid_str[36] != '\0') {
244
        /* ### need a better value */
245
0
        return OGS_ERROR;
246
0
    }
247
248
0
    d[0] = parse_hexpair(&uuid_str[0]);
249
0
    d[1] = parse_hexpair(&uuid_str[2]);
250
0
    d[2] = parse_hexpair(&uuid_str[4]);
251
0
    d[3] = parse_hexpair(&uuid_str[6]);
252
253
0
    d[4] = parse_hexpair(&uuid_str[9]);
254
0
    d[5] = parse_hexpair(&uuid_str[11]);
255
256
0
    d[6] = parse_hexpair(&uuid_str[14]);
257
0
    d[7] = parse_hexpair(&uuid_str[16]);
258
259
0
    d[8] = parse_hexpair(&uuid_str[19]);
260
0
    d[9] = parse_hexpair(&uuid_str[21]);
261
262
0
    for (i = 6; i--;)
263
0
        d[10 + i] = parse_hexpair(&uuid_str[i*2+24]);
264
265
0
    return OGS_OK;
266
0
}