line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/** |
2
|
|
|
|
|
|
|
* @file corelib.c |
3
|
|
|
|
|
|
|
* @version 950bba4 (HEAD -> master) |
4
|
|
|
|
|
|
|
* |
5
|
|
|
|
|
|
|
* Open and Close APIs and utilities for Matrix core library. |
6
|
|
|
|
|
|
|
*/ |
7
|
|
|
|
|
|
|
/* |
8
|
|
|
|
|
|
|
* Copyright (c) 2013-2017 INSIDE Secure Corporation |
9
|
|
|
|
|
|
|
* Copyright (c) PeerSec Networks, 2002-2011 |
10
|
|
|
|
|
|
|
* All Rights Reserved |
11
|
|
|
|
|
|
|
* |
12
|
|
|
|
|
|
|
* The latest version of this code is available at http://www.matrixssl.org |
13
|
|
|
|
|
|
|
* |
14
|
|
|
|
|
|
|
* This software is open source; you can redistribute it and/or modify |
15
|
|
|
|
|
|
|
* it under the terms of the GNU General Public License as published by |
16
|
|
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or |
17
|
|
|
|
|
|
|
* (at your option) any later version. |
18
|
|
|
|
|
|
|
* |
19
|
|
|
|
|
|
|
* This General Public License does NOT permit incorporating this software |
20
|
|
|
|
|
|
|
* into proprietary programs. If you are unable to comply with the GPL, a |
21
|
|
|
|
|
|
|
* commercial license for this software may be purchased from INSIDE at |
22
|
|
|
|
|
|
|
* http://www.insidesecure.com/ |
23
|
|
|
|
|
|
|
* |
24
|
|
|
|
|
|
|
* This program is distributed in WITHOUT ANY WARRANTY; without even the |
25
|
|
|
|
|
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
26
|
|
|
|
|
|
|
* See the GNU General Public License for more details. |
27
|
|
|
|
|
|
|
* |
28
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License |
29
|
|
|
|
|
|
|
* along with this program; if not, write to the Free Software |
30
|
|
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
31
|
|
|
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html |
32
|
|
|
|
|
|
|
*/ |
33
|
|
|
|
|
|
|
/******************************************************************************/ |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
#include "coreApi.h" |
36
|
|
|
|
|
|
|
#include "osdep.h" |
37
|
|
|
|
|
|
|
#include "psUtil.h" |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#ifdef USE_MULTITHREADING |
40
|
|
|
|
|
|
|
/* A mutex for concurrency control of functions implemented in this file. |
41
|
|
|
|
|
|
|
Obvious exception are psCoreOpen() and psCoreClose(). */ |
42
|
|
|
|
|
|
|
static psMutex_t corelibMutex; |
43
|
|
|
|
|
|
|
#endif /* USE_MULTITHREADING */ |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
/******************************************************************************/ |
46
|
|
|
|
|
|
|
/* |
47
|
|
|
|
|
|
|
Open (initialize) the Core module |
48
|
|
|
|
|
|
|
The config param should always be passed as: |
49
|
|
|
|
|
|
|
PSCORE_CONFIG |
50
|
|
|
|
|
|
|
*/ |
51
|
|
|
|
|
|
|
static char g_config[32] = "N"; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
/******************************************************************************/ |
54
|
17
|
|
|
|
|
|
int32 psCoreOpen(const char *config) |
55
|
|
|
|
|
|
|
{ |
56
|
17
|
50
|
|
|
|
|
if (*g_config == 'Y') |
57
|
|
|
|
|
|
|
{ |
58
|
0
|
|
|
|
|
|
return PS_CORE_IS_OPEN; |
59
|
|
|
|
|
|
|
} |
60
|
17
|
|
|
|
|
|
strncpy(g_config, PSCORE_CONFIG, sizeof(g_config) - 1); |
61
|
17
|
50
|
|
|
|
|
if (strncmp(g_config, config, strlen(PSCORE_CONFIG)) != 0) |
62
|
|
|
|
|
|
|
{ |
63
|
0
|
|
|
|
|
|
psErrorStr( "Core config mismatch.\n" \ |
64
|
|
|
|
|
|
|
"Library: " PSCORE_CONFIG \ |
65
|
|
|
|
|
|
|
"\nCurrent: %s\n", config); |
66
|
0
|
|
|
|
|
|
return -1; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
17
|
50
|
|
|
|
|
if (osdepTimeOpen() < 0) |
70
|
|
|
|
|
|
|
{ |
71
|
|
|
|
|
|
|
psTraceCore("osdepTimeOpen failed\n"); |
72
|
0
|
|
|
|
|
|
return PS_FAILURE; |
73
|
|
|
|
|
|
|
} |
74
|
17
|
50
|
|
|
|
|
if (osdepEntropyOpen() < 0) |
75
|
|
|
|
|
|
|
{ |
76
|
|
|
|
|
|
|
psTraceCore("osdepEntropyOpen failed\n"); |
77
|
0
|
|
|
|
|
|
osdepTimeClose(); |
78
|
0
|
|
|
|
|
|
return PS_FAILURE; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
#ifdef USE_MULTITHREADING |
82
|
|
|
|
|
|
|
if (osdepMutexOpen() < 0) |
83
|
|
|
|
|
|
|
{ |
84
|
|
|
|
|
|
|
psTraceCore("osdepMutexOpen failed\n"); |
85
|
|
|
|
|
|
|
osdepEntropyClose(); |
86
|
|
|
|
|
|
|
osdepTimeClose(); |
87
|
|
|
|
|
|
|
return PS_FAILURE; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
if (psCreateMutex(&corelibMutex, 0) < 0) |
90
|
|
|
|
|
|
|
{ |
91
|
|
|
|
|
|
|
psTraceCore("psCreateMutex failed\n"); |
92
|
|
|
|
|
|
|
osdepMutexClose(); |
93
|
|
|
|
|
|
|
osdepEntropyClose(); |
94
|
|
|
|
|
|
|
osdepTimeClose(); |
95
|
|
|
|
|
|
|
return PS_FAILURE; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
#endif /* USE_MULTITHREADING */ |
98
|
|
|
|
|
|
|
|
99
|
17
|
|
|
|
|
|
return PS_SUCCESS; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
/******************************************************************************/ |
103
|
14
|
|
|
|
|
|
void psCoreClose(void) |
104
|
|
|
|
|
|
|
{ |
105
|
14
|
50
|
|
|
|
|
if (*g_config == 'Y') |
106
|
|
|
|
|
|
|
{ |
107
|
14
|
|
|
|
|
|
*g_config = 'N'; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
#ifdef USE_MULTITHREADING |
110
|
|
|
|
|
|
|
psDestroyMutex(&corelibMutex); |
111
|
|
|
|
|
|
|
osdepMutexClose(); |
112
|
|
|
|
|
|
|
#endif /* USE_MULTITHREADING */ |
113
|
|
|
|
|
|
|
|
114
|
14
|
|
|
|
|
|
osdepEntropyClose(); |
115
|
|
|
|
|
|
|
|
116
|
14
|
|
|
|
|
|
osdepTimeClose(); |
117
|
|
|
|
|
|
|
} |
118
|
14
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
/******************************************************************************/ |
121
|
|
|
|
|
|
|
/** |
122
|
|
|
|
|
|
|
Constant time memory comparison - like memcmp but w/o data dependent branch. |
123
|
|
|
|
|
|
|
@security SECURITY - Should be used when comparing values that use or have |
124
|
|
|
|
|
|
|
been derived or have been decrypted/encrypted/signed from secret information. |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
@param[in] s1 Pointer to first buffer to compare |
127
|
|
|
|
|
|
|
@param[in] s2 Pointer to first buffer to compare |
128
|
|
|
|
|
|
|
@param[in] len number of bytes to compare in s1 and s2 |
129
|
|
|
|
|
|
|
@return 0 on successful match, nonzero on failure. |
130
|
|
|
|
|
|
|
*/ |
131
|
11783
|
|
|
|
|
|
int32 memcmpct(const void *s1, const void *s2, size_t len) |
132
|
|
|
|
|
|
|
{ |
133
|
11783
|
|
|
|
|
|
int xor = 0; |
134
|
|
|
|
|
|
|
|
135
|
267185
|
100
|
|
|
|
|
while (len > 0) |
136
|
|
|
|
|
|
|
{ |
137
|
255402
|
|
|
|
|
|
len--; |
138
|
255402
|
|
|
|
|
|
xor |= ((unsigned char *) s1)[len] ^ ((unsigned char *) s2)[len]; |
139
|
|
|
|
|
|
|
} |
140
|
11783
|
|
|
|
|
|
return xor; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
/******************************************************************************/ |
144
|
|
|
|
|
|
|
/* |
145
|
|
|
|
|
|
|
ERROR FUNCTIONS |
146
|
|
|
|
|
|
|
Tap into platform trace and break execution if DEBUG compile |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
Modules should tie themselves to these low levels |
149
|
|
|
|
|
|
|
with compile-time defines |
150
|
|
|
|
|
|
|
*/ |
151
|
0
|
|
|
|
|
|
void _psError(const char *msg) |
152
|
|
|
|
|
|
|
{ |
153
|
0
|
|
|
|
|
|
_psTrace(msg); |
154
|
0
|
|
|
|
|
|
_psTrace("\n"); |
155
|
|
|
|
|
|
|
#ifdef HALT_ON_PS_ERROR |
156
|
|
|
|
|
|
|
osdepBreak(); |
157
|
|
|
|
|
|
|
#endif |
158
|
0
|
|
|
|
|
|
} |
159
|
0
|
|
|
|
|
|
void _psErrorInt(const char *msg, int32 val) |
160
|
|
|
|
|
|
|
{ |
161
|
0
|
|
|
|
|
|
_psTraceInt(msg, val); |
162
|
0
|
|
|
|
|
|
_psTrace("\n"); |
163
|
|
|
|
|
|
|
#ifdef HALT_ON_PS_ERROR |
164
|
|
|
|
|
|
|
osdepBreak(); |
165
|
|
|
|
|
|
|
#endif |
166
|
0
|
|
|
|
|
|
} |
167
|
0
|
|
|
|
|
|
void _psErrorStr(const char *msg, const char *val) |
168
|
|
|
|
|
|
|
{ |
169
|
0
|
|
|
|
|
|
_psTraceStr(msg, val); |
170
|
0
|
|
|
|
|
|
_psTrace("\n"); |
171
|
|
|
|
|
|
|
#ifdef HALT_ON_PS_ERROR |
172
|
|
|
|
|
|
|
osdepBreak(); |
173
|
|
|
|
|
|
|
#endif |
174
|
0
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
/* |
177
|
|
|
|
|
|
|
copy 'len' bytes from 'b' to 's', converting all to printable characters |
178
|
|
|
|
|
|
|
*/ |
179
|
0
|
|
|
|
|
|
static void mem2str(char *s, const unsigned char *b, uint32 len) |
180
|
|
|
|
|
|
|
{ |
181
|
0
|
0
|
|
|
|
|
for (; len > 0; len--) |
182
|
|
|
|
|
|
|
{ |
183
|
0
|
0
|
|
|
|
|
if (*b > 31 && *b < 127) |
|
|
0
|
|
|
|
|
|
184
|
|
|
|
|
|
|
{ |
185
|
0
|
|
|
|
|
|
*s = *b; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
else |
188
|
|
|
|
|
|
|
{ |
189
|
0
|
|
|
|
|
|
*s = '.'; |
190
|
|
|
|
|
|
|
} |
191
|
0
|
|
|
|
|
|
b++; |
192
|
0
|
|
|
|
|
|
s++; |
193
|
|
|
|
|
|
|
} |
194
|
0
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
|
196
|
0
|
|
|
|
|
|
void psTraceBytes(const char *tag, const unsigned char *p, int l) |
197
|
|
|
|
|
|
|
{ |
198
|
|
|
|
|
|
|
char s[17]; |
199
|
|
|
|
|
|
|
int i; |
200
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
|
s[16] = '\0'; |
202
|
0
|
0
|
|
|
|
|
if (tag) |
203
|
|
|
|
|
|
|
{ |
204
|
0
|
|
|
|
|
|
_psTraceStr("psTraceBytes(%s, ", tag); |
205
|
0
|
|
|
|
|
|
_psTraceInt("%d);", l); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
else |
208
|
|
|
|
|
|
|
{ |
209
|
0
|
|
|
|
|
|
_psTrace("\""); |
210
|
|
|
|
|
|
|
} |
211
|
0
|
0
|
|
|
|
|
for (i = 0; i < l; i++) |
212
|
|
|
|
|
|
|
{ |
213
|
0
|
0
|
|
|
|
|
if (!(i & 0xF)) |
214
|
|
|
|
|
|
|
{ |
215
|
0
|
0
|
|
|
|
|
if (tag) |
216
|
|
|
|
|
|
|
{ |
217
|
0
|
0
|
|
|
|
|
if (i != 0) |
218
|
|
|
|
|
|
|
{ |
219
|
0
|
|
|
|
|
|
mem2str(s, p - 16, 16); |
220
|
0
|
|
|
|
|
|
_psTraceStr(" %s", s); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
#ifdef _LP64 |
223
|
0
|
|
|
|
|
|
_psTraceInt("\n0x%08x:", (int64) p); |
224
|
|
|
|
|
|
|
#else |
225
|
|
|
|
|
|
|
_psTraceInt("\n0x%04x:", (int32) p); |
226
|
|
|
|
|
|
|
#endif |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
else |
229
|
|
|
|
|
|
|
{ |
230
|
0
|
|
|
|
|
|
_psTrace("\"\n\""); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
} |
233
|
0
|
0
|
|
|
|
|
if (tag) |
234
|
|
|
|
|
|
|
{ |
235
|
0
|
|
|
|
|
|
_psTraceInt("%02x ", *p++); |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
else |
238
|
|
|
|
|
|
|
{ |
239
|
0
|
|
|
|
|
|
_psTraceInt("\\x%02x", *p++); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
} |
242
|
0
|
0
|
|
|
|
|
if (tag) |
243
|
|
|
|
|
|
|
{ |
244
|
0
|
|
|
|
|
|
memset(s, 0x0, 16); |
245
|
0
|
|
|
|
|
|
i = l & 0xF; |
246
|
0
|
|
|
|
|
|
mem2str(s, p - i, (unsigned int) i); |
247
|
0
|
0
|
|
|
|
|
for (; i < 16; i++) |
248
|
|
|
|
|
|
|
{ |
249
|
0
|
|
|
|
|
|
_psTrace(" "); |
250
|
|
|
|
|
|
|
} |
251
|
0
|
|
|
|
|
|
_psTraceStr(" %s", s); |
252
|
0
|
|
|
|
|
|
_psTrace("\n"); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
else |
255
|
|
|
|
|
|
|
{ |
256
|
0
|
|
|
|
|
|
_psTrace("\"\n"); |
257
|
|
|
|
|
|
|
} |
258
|
0
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
/******************************************************************************/ |
261
|
|
|
|
|
|
|
/* |
262
|
|
|
|
|
|
|
Creates a simple linked list from a given stream and separator char |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
Memory info: |
265
|
|
|
|
|
|
|
Callers do not have to free 'items' on function failure. |
266
|
|
|
|
|
|
|
*/ |
267
|
777
|
|
|
|
|
|
int32 psParseList(psPool_t *pool, char *list, const char separator, |
268
|
|
|
|
|
|
|
psList_t **items) |
269
|
|
|
|
|
|
|
{ |
270
|
|
|
|
|
|
|
psList_t *litems, *start, *prev; |
271
|
|
|
|
|
|
|
uint32 itemLen, listLen; |
272
|
|
|
|
|
|
|
char *tmp; |
273
|
|
|
|
|
|
|
|
274
|
777
|
|
|
|
|
|
*items = NULL; |
275
|
777
|
|
|
|
|
|
prev = NULL; |
276
|
|
|
|
|
|
|
|
277
|
777
|
|
|
|
|
|
listLen = (int32) strlen(list) + 1; |
278
|
777
|
50
|
|
|
|
|
if (listLen == 1) |
279
|
|
|
|
|
|
|
{ |
280
|
0
|
|
|
|
|
|
return PS_ARG_FAIL; |
281
|
|
|
|
|
|
|
} |
282
|
777
|
|
|
|
|
|
start = litems = psMalloc(pool, sizeof(psList_t)); |
283
|
777
|
50
|
|
|
|
|
if (litems == NULL) |
284
|
|
|
|
|
|
|
{ |
285
|
0
|
|
|
|
|
|
return PS_MEM_FAIL; |
286
|
|
|
|
|
|
|
} |
287
|
777
|
|
|
|
|
|
memset(litems, 0, sizeof(psList_t)); |
288
|
|
|
|
|
|
|
|
289
|
1554
|
100
|
|
|
|
|
while (listLen > 0) |
290
|
|
|
|
|
|
|
{ |
291
|
777
|
|
|
|
|
|
itemLen = 0; |
292
|
777
|
|
|
|
|
|
tmp = list; |
293
|
777
|
50
|
|
|
|
|
if (litems == NULL) |
294
|
|
|
|
|
|
|
{ |
295
|
0
|
|
|
|
|
|
litems = psMalloc(pool, sizeof(psList_t)); |
296
|
0
|
0
|
|
|
|
|
if (litems == NULL) |
297
|
|
|
|
|
|
|
{ |
298
|
0
|
|
|
|
|
|
psFreeList(start, pool); |
299
|
0
|
|
|
|
|
|
return PS_MEM_FAIL; |
300
|
|
|
|
|
|
|
} |
301
|
0
|
|
|
|
|
|
memset(litems, 0, sizeof(psList_t)); |
302
|
0
|
|
|
|
|
|
prev->next = litems; |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
} |
305
|
14428
|
50
|
|
|
|
|
while (*list != separator && *list != '\0') |
|
|
100
|
|
|
|
|
|
306
|
|
|
|
|
|
|
{ |
307
|
13651
|
|
|
|
|
|
itemLen++; |
308
|
13651
|
|
|
|
|
|
listLen--; |
309
|
13651
|
|
|
|
|
|
list++; |
310
|
|
|
|
|
|
|
} |
311
|
777
|
|
|
|
|
|
litems->item = psMalloc(pool, itemLen + 1); |
312
|
777
|
50
|
|
|
|
|
if (litems->item == NULL) |
313
|
|
|
|
|
|
|
{ |
314
|
0
|
|
|
|
|
|
psFreeList(start, pool); |
315
|
0
|
|
|
|
|
|
return PS_MEM_FAIL; |
316
|
|
|
|
|
|
|
} |
317
|
777
|
|
|
|
|
|
litems->len = itemLen; |
318
|
777
|
|
|
|
|
|
memset(litems->item, 0x0, itemLen + 1); |
319
|
777
|
|
|
|
|
|
memcpy(litems->item, tmp, itemLen); |
320
|
777
|
|
|
|
|
|
list++; |
321
|
777
|
|
|
|
|
|
listLen--; |
322
|
777
|
|
|
|
|
|
prev = litems; |
323
|
777
|
|
|
|
|
|
litems = litems->next; |
324
|
|
|
|
|
|
|
} |
325
|
777
|
|
|
|
|
|
*items = start; |
326
|
777
|
|
|
|
|
|
return PS_SUCCESS; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
1553
|
|
|
|
|
|
void psFreeList(psList_t *list, psPool_t *pool) |
330
|
|
|
|
|
|
|
{ |
331
|
|
|
|
|
|
|
psList_t *next, *current; |
332
|
|
|
|
|
|
|
|
333
|
1553
|
50
|
|
|
|
|
if (list == NULL) |
334
|
|
|
|
|
|
|
{ |
335
|
0
|
|
|
|
|
|
return; |
336
|
|
|
|
|
|
|
} |
337
|
1553
|
|
|
|
|
|
current = list; |
338
|
3826
|
100
|
|
|
|
|
while (current) |
339
|
|
|
|
|
|
|
{ |
340
|
2273
|
|
|
|
|
|
next = current->next; |
341
|
2273
|
100
|
|
|
|
|
if (current->item) |
342
|
|
|
|
|
|
|
{ |
343
|
2272
|
|
|
|
|
|
psFree(current->item, pool); |
344
|
|
|
|
|
|
|
} |
345
|
2273
|
|
|
|
|
|
psFree(current, pool); |
346
|
2273
|
|
|
|
|
|
current = next; |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
/******************************************************************************/ |
351
|
|
|
|
|
|
|
/* |
352
|
|
|
|
|
|
|
Clear the stack deeper than the caller to erase any potential secrets |
353
|
|
|
|
|
|
|
or keys. |
354
|
|
|
|
|
|
|
*/ |
355
|
17106413
|
|
|
|
|
|
void psBurnStack(uint32 len) |
356
|
|
|
|
|
|
|
{ |
357
|
|
|
|
|
|
|
unsigned char buf[32]; |
358
|
|
|
|
|
|
|
|
359
|
17106413
|
|
|
|
|
|
memset_s(buf, sizeof(buf), 0x0, sizeof(buf)); |
360
|
17106413
|
100
|
|
|
|
|
if (len > (uint32) sizeof(buf)) |
361
|
|
|
|
|
|
|
{ |
362
|
12190207
|
|
|
|
|
|
psBurnStack(len - sizeof(buf)); |
363
|
|
|
|
|
|
|
} |
364
|
17106413
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
/******************************************************************************/ |
367
|
|
|
|
|
|
|
/* |
368
|
|
|
|
|
|
|
Free pointed memory and clear the pointer to avoid accidental |
369
|
|
|
|
|
|
|
double free. |
370
|
|
|
|
|
|
|
*/ |
371
|
0
|
|
|
|
|
|
void psFreeAndClear(void *ptrptr, psPool_t *pool) |
372
|
|
|
|
|
|
|
{ |
373
|
|
|
|
|
|
|
void *ptr; |
374
|
|
|
|
|
|
|
|
375
|
0
|
0
|
|
|
|
|
if (ptrptr != NULL) |
376
|
|
|
|
|
|
|
{ |
377
|
0
|
|
|
|
|
|
ptr = *(void **) ptrptr; |
378
|
0
|
|
|
|
|
|
psFree(ptr, pool); |
379
|
0
|
|
|
|
|
|
*(void **) ptrptr = NULL; |
380
|
|
|
|
|
|
|
PS_PARAMETER_UNUSED(pool); /* Parameter can be unused. */ |
381
|
|
|
|
|
|
|
} |
382
|
0
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
#if defined __unix__ || defined __unix || (defined (__APPLE__) && defined (__MACH__)) |
385
|
|
|
|
|
|
|
# include /* Possibly provides _POSIX_VERSION. */ |
386
|
|
|
|
|
|
|
/* 32-bit Unix machines may need workaround for Year 2038. |
387
|
|
|
|
|
|
|
64-bit Unix machines generally use large enough time_t. */ |
388
|
|
|
|
|
|
|
# if !defined __LP64__ && !defined __ILP64__ |
389
|
|
|
|
|
|
|
# define USE_UNIX_Y2038_WORKAROUND 1 |
390
|
|
|
|
|
|
|
# endif |
391
|
|
|
|
|
|
|
#endif /* __unix__ */ |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
#ifdef _POSIX_VERSION |
394
|
|
|
|
|
|
|
# define USE_GMTIME_R /* On posix systems, we use gmtime_r() */ |
395
|
|
|
|
|
|
|
#endif /* _POSIX_VERSION */ |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
/******************************************************************************/ |
398
|
|
|
|
|
|
|
/* |
399
|
|
|
|
|
|
|
Get broken-down time, similar to time returned by gmtime(), but avoiding |
400
|
|
|
|
|
|
|
the race condition. The function only applies offset if it does not cause |
401
|
|
|
|
|
|
|
overflow. |
402
|
|
|
|
|
|
|
*/ |
403
|
2879
|
|
|
|
|
|
PSPUBLIC int32 psBrokenDownTimeImportSeconds(psBrokenDownTime_t *t, |
404
|
|
|
|
|
|
|
psTimeSeconds_t s) |
405
|
|
|
|
|
|
|
{ |
406
|
2879
|
|
|
|
|
|
int32 ret = PS_FAILURE; |
407
|
|
|
|
|
|
|
struct tm *tm; |
408
|
2879
|
|
|
|
|
|
time_t time = s; |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
#ifdef USE_GMTIME_R |
411
|
|
|
|
|
|
|
/* Note: This command assumes psBrokenDownTime_t and struct tm use |
412
|
|
|
|
|
|
|
exactly the same representation. If you optimize storage space of |
413
|
|
|
|
|
|
|
psBrokenDownTime_t, then transfer each field separately. */ |
414
|
2879
|
|
|
|
|
|
tm = gmtime_r(&time, t); |
415
|
2879
|
50
|
|
|
|
|
if (tm != NULL) |
416
|
|
|
|
|
|
|
{ |
417
|
2879
|
|
|
|
|
|
ret = PS_SUCCESS; |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
#else |
420
|
|
|
|
|
|
|
/* Use mutex to lock. */ |
421
|
|
|
|
|
|
|
psLockMutex(&corelibMutex); |
422
|
|
|
|
|
|
|
tm = gmtime(&time); |
423
|
|
|
|
|
|
|
if (tm) |
424
|
|
|
|
|
|
|
{ |
425
|
|
|
|
|
|
|
/* Note: This command assumes psBrokenDownTime_t and struct tm use |
426
|
|
|
|
|
|
|
exactly the same representation. If you optimize storage space of |
427
|
|
|
|
|
|
|
psBrokenDownTime_t, then transfer each field separately. */ |
428
|
|
|
|
|
|
|
memcpy(t, tm, sizeof(*t)); |
429
|
|
|
|
|
|
|
ret = PS_SUCCESS; |
430
|
|
|
|
|
|
|
} |
431
|
|
|
|
|
|
|
psUnlockMutex(&corelibMutex); |
432
|
|
|
|
|
|
|
#endif |
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
#ifdef USE_UNIX_Y2038_WORKAROUND |
435
|
|
|
|
|
|
|
/* Workaround for time_t overflow in 2038 on 32-bit Linux/Unix: */ |
436
|
|
|
|
|
|
|
if (time < 0 && t->tm_year < 70) |
437
|
|
|
|
|
|
|
{ |
438
|
|
|
|
|
|
|
/* Overflow of dat has occurred. Fix the date, using |
439
|
|
|
|
|
|
|
psBrokenDownTimeAdd(). This may possibly result in an estimate |
440
|
|
|
|
|
|
|
because the computation here does not know of details like |
441
|
|
|
|
|
|
|
leap seconds assigned in future. The result should be precise to |
442
|
|
|
|
|
|
|
few seconds. */ |
443
|
|
|
|
|
|
|
/* Note: Adjustment in three parts, because adjustment is too large |
444
|
|
|
|
|
|
|
to be processed at once. |
445
|
|
|
|
|
|
|
Note: 0x100000000 == 883612800 * 4 + 760516096. */ |
446
|
|
|
|
|
|
|
(void) psBrokenDownTimeAdd(t, 883612800 * 2); |
447
|
|
|
|
|
|
|
(void) psBrokenDownTimeAdd(t, 883612800 * 2); |
448
|
|
|
|
|
|
|
(void) psBrokenDownTimeAdd(t, 760516096); |
449
|
|
|
|
|
|
|
} |
450
|
|
|
|
|
|
|
#endif /* USE_UNIX_Y2038_WORKAROUND */ |
451
|
2879
|
|
|
|
|
|
return ret; |
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
/* |
455
|
|
|
|
|
|
|
Get broken-down time, similar to time returned by gmtime(), but avoiding |
456
|
|
|
|
|
|
|
the race condition. The function only applies offset if it does not cause |
457
|
|
|
|
|
|
|
overflow. |
458
|
|
|
|
|
|
|
*/ |
459
|
2879
|
|
|
|
|
|
PSPUBLIC int32 psGetBrokenDownGMTime(psBrokenDownTime_t *t, int offset) |
460
|
|
|
|
|
|
|
{ |
461
|
|
|
|
|
|
|
int32 ret; |
462
|
|
|
|
|
|
|
time_t current_time; |
463
|
|
|
|
|
|
|
psTimeSeconds_t offseted_time; |
464
|
|
|
|
|
|
|
|
465
|
2879
|
|
|
|
|
|
current_time = time(NULL); |
466
|
2879
|
50
|
|
|
|
|
if (current_time == ((time_t) -1)) |
467
|
|
|
|
|
|
|
{ |
468
|
0
|
|
|
|
|
|
return PS_FAILURE; |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
/* Handle negative offsets here. */ |
472
|
2879
|
|
|
|
|
|
offseted_time = ((psTimeSeconds_t) current_time) + offset; |
473
|
|
|
|
|
|
|
/* In case of overflow or positive offset, use time without offset. */ |
474
|
2879
|
50
|
|
|
|
|
if ((offset < 0 && offseted_time > current_time) || (offset > 0)) |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
475
|
|
|
|
|
|
|
{ |
476
|
0
|
|
|
|
|
|
offseted_time = current_time; |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
|
479
|
2879
|
|
|
|
|
|
ret = psBrokenDownTimeImportSeconds(t, offseted_time); |
480
|
|
|
|
|
|
|
/* Handle positive offsets here. */ |
481
|
2879
|
50
|
|
|
|
|
if (ret == PS_SUCCESS && offset > 0) |
|
|
50
|
|
|
|
|
|
482
|
|
|
|
|
|
|
{ |
483
|
0
|
|
|
|
|
|
ret = psBrokenDownTimeAdd(t, offset); |
484
|
|
|
|
|
|
|
} |
485
|
2879
|
|
|
|
|
|
return ret; |
486
|
|
|
|
|
|
|
} |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
/* Compute number of days in month. */ |
489
|
12974
|
|
|
|
|
|
static int mdays(const psBrokenDownTime_t *t) |
490
|
|
|
|
|
|
|
{ |
491
|
|
|
|
|
|
|
static unsigned char days_tab[] = { |
492
|
|
|
|
|
|
|
/* Jan */ 31, /* Most Feb */ 28,31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
493
|
|
|
|
|
|
|
}; |
494
|
|
|
|
|
|
|
unsigned char days; |
495
|
|
|
|
|
|
|
|
496
|
12974
|
50
|
|
|
|
|
if (t->tm_mon > 11) |
497
|
|
|
|
|
|
|
{ |
498
|
0
|
|
|
|
|
|
return -1; |
499
|
|
|
|
|
|
|
} |
500
|
12974
|
|
|
|
|
|
days = days_tab[t->tm_mon]; |
501
|
12974
|
100
|
|
|
|
|
if (days == 28) |
502
|
|
|
|
|
|
|
{ |
503
|
|
|
|
|
|
|
/* Note: This computation does not consider possible corrections once |
504
|
|
|
|
|
|
|
every 3200 years. */ |
505
|
70
|
|
|
|
|
|
int year = t->tm_year + 1900; |
506
|
70
|
100
|
|
|
|
|
int is_leap_year = (year % 4) == 0 && |
|
|
50
|
|
|
|
|
|
507
|
0
|
0
|
|
|
|
|
((year % 100) != 0 || (year % 400) == 0); |
508
|
70
|
|
|
|
|
|
days += is_leap_year; |
509
|
|
|
|
|
|
|
} |
510
|
12974
|
|
|
|
|
|
return days; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
/******************************************************************************/ |
514
|
|
|
|
|
|
|
/* |
515
|
|
|
|
|
|
|
Compute broken-down time, with specified offset. The initial broken |
516
|
|
|
|
|
|
|
down time t must have been previously initialized. This function only |
517
|
|
|
|
|
|
|
needs to support positive offset (including 0). |
518
|
|
|
|
|
|
|
*/ |
519
|
5758
|
|
|
|
|
|
PSPUBLIC int32 psBrokenDownTimeAdd(psBrokenDownTime_t *res, int32 offset) |
520
|
|
|
|
|
|
|
{ |
521
|
5758
|
50
|
|
|
|
|
if (offset < 0) |
522
|
|
|
|
|
|
|
{ |
523
|
0
|
|
|
|
|
|
return PS_FAILURE; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
/* Quick path for multiples of 28 years. */ |
527
|
5758
|
50
|
|
|
|
|
while (offset > 883612800) |
528
|
|
|
|
|
|
|
{ |
529
|
|
|
|
|
|
|
/* Quick addition of exactly 28 years (the cycle of Gregorian calendar, |
530
|
|
|
|
|
|
|
7 * 4 * 365.25 * 24 * 60 * 60 seconds). */ |
531
|
0
|
|
|
|
|
|
offset -= 883612800; |
532
|
0
|
|
|
|
|
|
res->tm_year += 28; |
533
|
|
|
|
|
|
|
} |
534
|
|
|
|
|
|
|
|
535
|
5758
|
50
|
|
|
|
|
if (offset == 0) |
536
|
|
|
|
|
|
|
{ |
537
|
0
|
|
|
|
|
|
return PS_SUCCESS; |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
/* Note: this function is approximate in presence of leap seconds. */ |
541
|
5758
|
|
|
|
|
|
res->tm_sec += offset; |
542
|
5758
|
50
|
|
|
|
|
if (res->tm_sec >= 60) |
543
|
|
|
|
|
|
|
{ |
544
|
5758
|
|
|
|
|
|
res->tm_min += res->tm_sec / 60; |
545
|
5758
|
|
|
|
|
|
res->tm_sec %= 60; |
546
|
|
|
|
|
|
|
} |
547
|
5758
|
50
|
|
|
|
|
if (res->tm_min >= 60) |
548
|
|
|
|
|
|
|
{ |
549
|
5758
|
|
|
|
|
|
res->tm_hour += res->tm_min / 60; |
550
|
5758
|
|
|
|
|
|
res->tm_min %= 60; |
551
|
|
|
|
|
|
|
} |
552
|
5758
|
50
|
|
|
|
|
if (res->tm_hour >= 24) |
553
|
|
|
|
|
|
|
{ |
554
|
5758
|
|
|
|
|
|
res->tm_mday += res->tm_hour / 24; |
555
|
5758
|
|
|
|
|
|
res->tm_wday += res->tm_hour / 24; |
556
|
5758
|
|
|
|
|
|
res->tm_wday %= 7; |
557
|
5758
|
|
|
|
|
|
res->tm_hour %= 24; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
/* Do month days, months & years as a loop. */ |
560
|
5913
|
100
|
|
|
|
|
while (res->tm_mday > mdays(res)) |
561
|
|
|
|
|
|
|
{ |
562
|
155
|
|
|
|
|
|
res->tm_mday -= mdays(res); |
563
|
155
|
|
|
|
|
|
res->tm_mon += 1; |
564
|
155
|
100
|
|
|
|
|
if (res->tm_mon > 11) |
565
|
|
|
|
|
|
|
{ |
566
|
115
|
|
|
|
|
|
res->tm_mon -= 12; |
567
|
115
|
|
|
|
|
|
res->tm_year++; |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
/* Note: tm_yday is not updated. */ |
570
|
155
|
|
|
|
|
|
res->tm_hour %= 60; |
571
|
|
|
|
|
|
|
} |
572
|
5758
|
|
|
|
|
|
return PS_SUCCESS; |
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
|
575
|
|
|
|
|
|
|
/******************************************************************************/ |
576
|
|
|
|
|
|
|
/* |
577
|
|
|
|
|
|
|
Format BrokenDown Time String with 4 digit year. |
578
|
|
|
|
|
|
|
The string format will be "YYYYMMDDHHMMSSZ". Z and NIL are included. |
579
|
|
|
|
|
|
|
*/ |
580
|
11516
|
|
|
|
|
|
PSPUBLIC int32 psBrokenDownTimeStr(const psBrokenDownTime_t *t, |
581
|
|
|
|
|
|
|
char (*string)[PS_BROKENDOWN_TIME_STR_LEN]) |
582
|
|
|
|
|
|
|
{ |
583
|
11516
|
|
|
|
|
|
size_t len = strftime(*string, PS_BROKENDOWN_TIME_STR_LEN, |
584
|
|
|
|
|
|
|
"%Y%m%d%H%M%SZ", t); |
585
|
|
|
|
|
|
|
|
586
|
11516
|
50
|
|
|
|
|
return len == PS_BROKENDOWN_TIME_STR_LEN - 1 ? PS_SUCCESS : PS_FAILURE; |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
/* Helper function to read specified amount of digits. |
590
|
|
|
|
|
|
|
The number read shall be within boundaries. On parse errors function returns |
591
|
|
|
|
|
|
|
(unsigned) -1, otherwise the parsed number. */ |
592
|
41436
|
|
|
|
|
|
static unsigned parse_digits( |
593
|
|
|
|
|
|
|
const unsigned char **c_p, |
594
|
|
|
|
|
|
|
unsigned digits, unsigned minimum, unsigned maximum) |
595
|
|
|
|
|
|
|
{ |
596
|
41436
|
|
|
|
|
|
const unsigned char *c = *c_p; |
597
|
41436
|
|
|
|
|
|
unsigned result = 0; |
598
|
|
|
|
|
|
|
|
599
|
124348
|
100
|
|
|
|
|
while (digits) |
600
|
|
|
|
|
|
|
{ |
601
|
82912
|
50
|
|
|
|
|
if (*c < '0' || *c > '9') |
|
|
50
|
|
|
|
|
|
602
|
|
|
|
|
|
|
{ |
603
|
0
|
|
|
|
|
|
return (unsigned) -1; |
604
|
|
|
|
|
|
|
} |
605
|
82912
|
|
|
|
|
|
result *= 10; |
606
|
82912
|
|
|
|
|
|
result += *c - '0'; |
607
|
82912
|
|
|
|
|
|
c++; |
608
|
82912
|
|
|
|
|
|
digits--; |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
|
611
|
41436
|
|
|
|
|
|
*c_p = c; |
612
|
|
|
|
|
|
|
|
613
|
41436
|
50
|
|
|
|
|
if (result < minimum || result > maximum) |
|
|
50
|
|
|
|
|
|
614
|
|
|
|
|
|
|
{ |
615
|
0
|
|
|
|
|
|
return (unsigned) -1; |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
41436
|
|
|
|
|
|
return result; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
/******************************************************************************/ |
622
|
|
|
|
|
|
|
/** |
623
|
|
|
|
|
|
|
Verify a string has nearly valid date range format and length, |
624
|
|
|
|
|
|
|
and return it in broken-down time format. |
625
|
|
|
|
|
|
|
*/ |
626
|
6906
|
|
|
|
|
|
static unsigned char parsedate_zulu(const unsigned char *p, |
627
|
|
|
|
|
|
|
unsigned int time_len, |
628
|
|
|
|
|
|
|
unsigned int year_len, |
629
|
|
|
|
|
|
|
psBrokenDownTime_t *target, |
630
|
|
|
|
|
|
|
int strict) |
631
|
|
|
|
|
|
|
{ |
632
|
|
|
|
|
|
|
unsigned year, month, mday, hour, min, sec; |
633
|
6906
|
|
|
|
|
|
const unsigned char *c = p; |
634
|
|
|
|
|
|
|
psBrokenDownTime_t check_only; |
635
|
|
|
|
|
|
|
|
636
|
6906
|
50
|
|
|
|
|
if (!target) |
637
|
|
|
|
|
|
|
{ |
638
|
|
|
|
|
|
|
/* Use check_only as target. */ |
639
|
0
|
|
|
|
|
|
target = &check_only; |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
/* Zeroize all fields as some systems have extra fields |
643
|
|
|
|
|
|
|
in struct tm. */ |
644
|
6906
|
|
|
|
|
|
memset(target, 0, sizeof(*target)); |
645
|
|
|
|
|
|
|
|
646
|
6906
|
100
|
|
|
|
|
if (year_len == 4) |
647
|
|
|
|
|
|
|
{ |
648
|
|
|
|
|
|
|
/* Format shall be YYYYMMDDHHMMSSZ (according to RFC 5280). */ |
649
|
20
|
50
|
|
|
|
|
if (time_len != 15 && strict) |
|
|
0
|
|
|
|
|
|
650
|
|
|
|
|
|
|
{ |
651
|
0
|
|
|
|
|
|
return 0; |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
/* Flexible: allow Z to be replaced with anything. */ |
654
|
20
|
50
|
|
|
|
|
if (time_len < 14 && !strict) |
|
|
0
|
|
|
|
|
|
655
|
|
|
|
|
|
|
{ |
656
|
0
|
|
|
|
|
|
return 0; |
657
|
|
|
|
|
|
|
} |
658
|
20
|
|
|
|
|
|
year = parse_digits(&c, 4, 1900, 2999); |
659
|
|
|
|
|
|
|
} |
660
|
6886
|
50
|
|
|
|
|
else if (year_len == 2) |
661
|
|
|
|
|
|
|
{ |
662
|
|
|
|
|
|
|
/* Format shall be YYMMDDHHMMSSZ (according to RFC 5280). */ |
663
|
6886
|
50
|
|
|
|
|
if (time_len != 13 && strict) |
|
|
0
|
|
|
|
|
|
664
|
|
|
|
|
|
|
{ |
665
|
0
|
|
|
|
|
|
return 0; |
666
|
|
|
|
|
|
|
} |
667
|
6886
|
50
|
|
|
|
|
if (time_len < 12 && !strict) |
|
|
0
|
|
|
|
|
|
668
|
|
|
|
|
|
|
{ |
669
|
0
|
|
|
|
|
|
return 0; |
670
|
|
|
|
|
|
|
} |
671
|
6886
|
|
|
|
|
|
year = parse_digits(&c, 2, 0, 99); |
672
|
|
|
|
|
|
|
} |
673
|
|
|
|
|
|
|
else |
674
|
|
|
|
|
|
|
{ |
675
|
0
|
|
|
|
|
|
return 0; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
6906
|
50
|
|
|
|
|
if (year == (unsigned) -1) |
679
|
|
|
|
|
|
|
{ |
680
|
0
|
|
|
|
|
|
return 0; |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
|
683
|
6906
|
|
|
|
|
|
month = parse_digits(&c, 2, 1, 12); |
684
|
6906
|
50
|
|
|
|
|
if (month == (unsigned) -1) |
685
|
|
|
|
|
|
|
{ |
686
|
0
|
|
|
|
|
|
return 0; |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
|
689
|
6906
|
|
|
|
|
|
mday = parse_digits(&c, 2, 1, 31); |
690
|
6906
|
50
|
|
|
|
|
if (mday == (unsigned) -1) |
691
|
|
|
|
|
|
|
{ |
692
|
0
|
|
|
|
|
|
return 0; |
693
|
|
|
|
|
|
|
} |
694
|
|
|
|
|
|
|
|
695
|
6906
|
|
|
|
|
|
hour = parse_digits(&c, 2, 0, 23); |
696
|
6906
|
50
|
|
|
|
|
if (hour == (unsigned) -1) |
697
|
|
|
|
|
|
|
{ |
698
|
0
|
|
|
|
|
|
return 0; |
699
|
|
|
|
|
|
|
} |
700
|
|
|
|
|
|
|
|
701
|
6906
|
|
|
|
|
|
min = parse_digits(&c, 2, 0, 59); |
702
|
6906
|
50
|
|
|
|
|
if (min == (unsigned) -1) |
703
|
|
|
|
|
|
|
{ |
704
|
0
|
|
|
|
|
|
return 0; |
705
|
|
|
|
|
|
|
} |
706
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
/* This allows up-to 1 leap second. |
708
|
|
|
|
|
|
|
(Note: could check that leap second only occurs at 23:59:60 on |
709
|
|
|
|
|
|
|
end of Jun 30 or Dec 31 (such as on 31 Dec 2016 23:59:60), but |
710
|
|
|
|
|
|
|
rules for insertion of leap seconds may change. */ |
711
|
6906
|
|
|
|
|
|
sec = parse_digits(&c, 2, 0, 60); |
712
|
6906
|
50
|
|
|
|
|
if (sec == (unsigned) -1) |
713
|
|
|
|
|
|
|
{ |
714
|
0
|
|
|
|
|
|
return 0; |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
/* Require all times in X.509 materials to be Zulu time, as is correct |
718
|
|
|
|
|
|
|
according to RFC 5280. */ |
719
|
6906
|
50
|
|
|
|
|
if (strict && *c != 'Z') |
|
|
0
|
|
|
|
|
|
720
|
|
|
|
|
|
|
{ |
721
|
0
|
|
|
|
|
|
return 0; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
else |
724
|
|
|
|
|
|
|
{ |
725
|
|
|
|
|
|
|
/* Ignore time zone. The time zone shall be Zulu according to RFC 5280, |
726
|
|
|
|
|
|
|
for X.509 certificates, CRL, OCSP etc. These times will be matched |
727
|
|
|
|
|
|
|
exactly. However, some old systems may use certificates with some |
728
|
|
|
|
|
|
|
other time zone. When handling those, the times will not be handled |
729
|
|
|
|
|
|
|
exactly, but the inaccuracy will be within a day. */ |
730
|
|
|
|
|
|
|
} |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
/* Convert 2 or 4 digit year to tm format (year after 1900). |
733
|
|
|
|
|
|
|
Two digit years are interpreted according to RFC 5280. */ |
734
|
6906
|
100
|
|
|
|
|
if (year < 50) |
735
|
|
|
|
|
|
|
{ |
736
|
6861
|
|
|
|
|
|
year += 100; |
737
|
|
|
|
|
|
|
} |
738
|
45
|
100
|
|
|
|
|
else if (year >= 1900) |
739
|
|
|
|
|
|
|
{ |
740
|
20
|
|
|
|
|
|
year -= 1900; |
741
|
|
|
|
|
|
|
} |
742
|
25
|
50
|
|
|
|
|
else if (year >= 100) |
743
|
|
|
|
|
|
|
{ |
744
|
|
|
|
|
|
|
/* years 100-1900 cannot be represented in psBrokenDownTime_t. */ |
745
|
0
|
|
|
|
|
|
return 0; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
else |
748
|
|
|
|
|
|
|
{ |
749
|
|
|
|
|
|
|
/* Two digit year 50-99 is already correct. */ |
750
|
|
|
|
|
|
|
} |
751
|
|
|
|
|
|
|
|
752
|
6906
|
|
|
|
|
|
target->tm_year = (int) year; |
753
|
6906
|
|
|
|
|
|
target->tm_mon = (int) month - 1; |
754
|
6906
|
|
|
|
|
|
target->tm_mday = (int) mday; |
755
|
6906
|
|
|
|
|
|
target->tm_hour = (int) hour; |
756
|
6906
|
|
|
|
|
|
target->tm_min = (int) min; |
757
|
6906
|
|
|
|
|
|
target->tm_sec = (int) sec; |
758
|
|
|
|
|
|
|
/* Note: target->tm_wday and target->tm_yday are not set. */ |
759
|
6906
|
50
|
|
|
|
|
if (target->tm_mday > mdays(target)) |
760
|
|
|
|
|
|
|
{ |
761
|
|
|
|
|
|
|
/* No such day in this month. */ |
762
|
0
|
|
|
|
|
|
memset(target, 0, sizeof(*target)); |
763
|
0
|
|
|
|
|
|
return 0; |
764
|
|
|
|
|
|
|
} |
765
|
6906
|
|
|
|
|
|
return 1; |
766
|
|
|
|
|
|
|
} |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
/******************************************************************************/ |
769
|
|
|
|
|
|
|
/* |
770
|
|
|
|
|
|
|
Import BrokenDown Time from String format. Number of digits in year |
771
|
|
|
|
|
|
|
can be provided via an option. The string format recommended is |
772
|
|
|
|
|
|
|
"YYYYMMDDHHMMSSZ". |
773
|
|
|
|
|
|
|
This function only supports Zulu time, any other time zone will be ignored. |
774
|
|
|
|
|
|
|
*/ |
775
|
6906
|
|
|
|
|
|
PSPUBLIC int32 psBrokenDownTimeImport( |
776
|
|
|
|
|
|
|
psBrokenDownTime_t *t, |
777
|
|
|
|
|
|
|
const char *string, size_t time_string_len, |
778
|
|
|
|
|
|
|
unsigned int opts) |
779
|
|
|
|
|
|
|
{ |
780
|
|
|
|
|
|
|
unsigned char res; |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
/* Reject very long strings as illegal. */ |
783
|
6906
|
50
|
|
|
|
|
if (time_string_len > 255) |
784
|
|
|
|
|
|
|
{ |
785
|
0
|
|
|
|
|
|
return PS_FAILURE; |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
|
788
|
6906
|
100
|
|
|
|
|
res = parsedate_zulu((const unsigned char *) string, |
789
|
|
|
|
|
|
|
(unsigned int) time_string_len, |
790
|
6906
|
|
|
|
|
|
(opts & PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR) ? |
791
|
|
|
|
|
|
|
2 : 4, t, |
792
|
|
|
|
|
|
|
(opts & PS_BROKENDOWN_TIME_IMPORT_STRICT_ZULU)); |
793
|
|
|
|
|
|
|
|
794
|
6906
|
50
|
|
|
|
|
return res ? PS_SUCCESS : PS_FAILURE; |
795
|
|
|
|
|
|
|
} |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
/******************************************************************************/ |
798
|
|
|
|
|
|
|
/* |
799
|
|
|
|
|
|
|
Compute broken-down times, returning <0, 0 or >0 according to t1 being |
800
|
|
|
|
|
|
|
smaller, equal or greater than t2. |
801
|
|
|
|
|
|
|
*/ |
802
|
5758
|
|
|
|
|
|
PSPUBLIC int psBrokenDownTimeCmp(const psBrokenDownTime_t *t1, |
803
|
|
|
|
|
|
|
const psBrokenDownTime_t *t2) |
804
|
|
|
|
|
|
|
{ |
805
|
5758
|
|
|
|
|
|
char s1[PS_BROKENDOWN_TIME_STR_LEN] = { '!', 0 }; |
806
|
5758
|
|
|
|
|
|
char s2[PS_BROKENDOWN_TIME_STR_LEN] = { 0 }; |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
/* The dates are represented using YYYYMMDDHHMMSSZ for comparison. |
809
|
|
|
|
|
|
|
I.e. comparison ignores tm_wday, tm_yday, and tm_isdst. */ |
810
|
5758
|
|
|
|
|
|
(void) psBrokenDownTimeStr(t1, &s1); |
811
|
5758
|
|
|
|
|
|
(void) psBrokenDownTimeStr(t2, &s2); |
812
|
|
|
|
|
|
|
/* If you wish to debug time comparisons, you can enable next lines. */ |
813
|
|
|
|
|
|
|
/* _psTraceStr("Comparing t1: %s against ", s1); */ |
814
|
|
|
|
|
|
|
/* _psTraceStr("t2: %s ", s2); */ |
815
|
|
|
|
|
|
|
/* _psTraceInt("got: %d\n", memcmp(s1, s2, sizeof(s1))); */ |
816
|
5758
|
|
|
|
|
|
return memcmp(s1, s2, sizeof(s1)); |
817
|
|
|
|
|
|
|
} |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
/******************************************************************************/ |
820
|
|
|
|
|
|
|
/* |
821
|
|
|
|
|
|
|
Helper function for String conversion. |
822
|
|
|
|
|
|
|
*/ |
823
|
0
|
|
|
|
|
|
PSPUBLIC int32 psToUtf8String(psPool_t *pool, |
824
|
|
|
|
|
|
|
const unsigned char *input, size_t input_len, |
825
|
|
|
|
|
|
|
psStringType_t input_type, |
826
|
|
|
|
|
|
|
unsigned char **output, size_t *output_len, |
827
|
|
|
|
|
|
|
int opts) |
828
|
|
|
|
|
|
|
{ |
829
|
|
|
|
|
|
|
int32 err; |
830
|
|
|
|
|
|
|
psParseBuf_t in; |
831
|
|
|
|
|
|
|
psDynBuf_t out; |
832
|
|
|
|
|
|
|
size_t ignored_size; |
833
|
0
|
|
|
|
|
|
int clen = 1; |
834
|
|
|
|
|
|
|
|
835
|
0
|
0
|
|
|
|
|
if ((opts & ~PS_STRING_DUAL_NIL) != 0) |
836
|
|
|
|
|
|
|
{ |
837
|
0
|
|
|
|
|
|
return PS_UNSUPPORTED_FAIL; |
838
|
|
|
|
|
|
|
} |
839
|
|
|
|
|
|
|
|
840
|
0
|
|
|
|
|
|
switch (input_type) |
841
|
|
|
|
|
|
|
{ |
842
|
|
|
|
|
|
|
case PS_STRING_NUMERIC_STRING: |
843
|
|
|
|
|
|
|
case PS_STRING_PRINTABLE_STRING: |
844
|
|
|
|
|
|
|
/* These are subsets of ASCII. */ |
845
|
0
|
|
|
|
|
|
break; |
846
|
|
|
|
|
|
|
case PS_STRING_BMP_STRING: |
847
|
|
|
|
|
|
|
/* UCS2 characters. */ |
848
|
0
|
|
|
|
|
|
clen = 2; |
849
|
0
|
|
|
|
|
|
break; |
850
|
|
|
|
|
|
|
default: |
851
|
0
|
|
|
|
|
|
return PS_UNSUPPORTED_FAIL; |
852
|
|
|
|
|
|
|
} |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
/* Sequence of 16-bit characters has to have even length. */ |
855
|
0
|
0
|
|
|
|
|
if (clen == 2 && (input_len & 1) > 0) |
|
|
0
|
|
|
|
|
|
856
|
|
|
|
|
|
|
{ |
857
|
0
|
|
|
|
|
|
return PS_FAILURE; |
858
|
|
|
|
|
|
|
} |
859
|
|
|
|
|
|
|
|
860
|
0
|
|
|
|
|
|
err = psParseBufFromStaticData(&in, input, input_len); |
861
|
0
|
0
|
|
|
|
|
if (err != PS_SUCCESS) |
862
|
|
|
|
|
|
|
{ |
863
|
0
|
|
|
|
|
|
return err; |
864
|
|
|
|
|
|
|
} |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
/* Create dynamic buffer with initial size estimate being the same |
867
|
|
|
|
|
|
|
than input + termination character(s). */ |
868
|
0
|
0
|
|
|
|
|
err = psDynBufInit(pool, &out, input_len + 2) ? PS_SUCCESS : PS_MEM_FAIL; |
869
|
0
|
0
|
|
|
|
|
if (err != PS_SUCCESS) |
870
|
|
|
|
|
|
|
{ |
871
|
0
|
|
|
|
|
|
return err; |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
0
|
0
|
|
|
|
|
if (clen == 1) |
875
|
|
|
|
|
|
|
{ |
876
|
0
|
0
|
|
|
|
|
while (psParseCanRead(&in, 1)) |
877
|
|
|
|
|
|
|
{ |
878
|
0
|
|
|
|
|
|
int8_t chr = (int8_t) *in.buf.start; |
879
|
0
|
0
|
|
|
|
|
if (chr >= 1) |
880
|
|
|
|
|
|
|
{ |
881
|
0
|
|
|
|
|
|
(void) psDynBufAppendChar(&out, (char) chr); |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
else |
884
|
|
|
|
|
|
|
{ |
885
|
|
|
|
|
|
|
/* non-ASCII character (eight bit set) or \0. */ |
886
|
0
|
|
|
|
|
|
err = PS_LIMIT_FAIL; |
887
|
|
|
|
|
|
|
} |
888
|
0
|
|
|
|
|
|
psParseBufSkipBytes(&in, (unsigned char *) &chr, 1); |
889
|
|
|
|
|
|
|
} |
890
|
|
|
|
|
|
|
} |
891
|
|
|
|
|
|
|
else /* clen == 2 */ |
892
|
|
|
|
|
|
|
{ |
893
|
0
|
0
|
|
|
|
|
while (psParseCanRead(&in, 2)) |
894
|
|
|
|
|
|
|
{ |
895
|
|
|
|
|
|
|
unsigned char a[2]; |
896
|
|
|
|
|
|
|
uint16_t chr; |
897
|
0
|
|
|
|
|
|
memcpy(a, in.buf.start, 2); |
898
|
0
|
|
|
|
|
|
chr = a[0]; |
899
|
0
|
|
|
|
|
|
chr <<= 8; |
900
|
0
|
|
|
|
|
|
chr |= a[1]; |
901
|
0
|
0
|
|
|
|
|
if (chr != 0 && (chr < 0xd800 || chr > 0xdfff)) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
902
|
|
|
|
|
|
|
{ |
903
|
|
|
|
|
|
|
/* ASCII */ |
904
|
0
|
|
|
|
|
|
(void) psDynBufAppendUtf8(&out, chr); |
905
|
|
|
|
|
|
|
} |
906
|
|
|
|
|
|
|
else |
907
|
|
|
|
|
|
|
{ |
908
|
|
|
|
|
|
|
/* surrogate pair or \0. These are invalid code points BMP. */ |
909
|
0
|
|
|
|
|
|
err = PS_LIMIT_FAIL; |
910
|
|
|
|
|
|
|
} |
911
|
0
|
|
|
|
|
|
psParseBufSkipBytes(&in, a, 2); |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
} |
914
|
|
|
|
|
|
|
|
915
|
0
|
0
|
|
|
|
|
if (output_len == NULL) |
916
|
|
|
|
|
|
|
{ |
917
|
0
|
|
|
|
|
|
output_len = &ignored_size; |
918
|
|
|
|
|
|
|
} |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
/* Append terminating \0 or \0\0. */ |
921
|
0
|
|
|
|
|
|
psDynBufAppendChar(&out, 0); |
922
|
0
|
0
|
|
|
|
|
if ((opts & PS_STRING_DUAL_NIL) != 0) |
923
|
|
|
|
|
|
|
{ |
924
|
0
|
|
|
|
|
|
psDynBufAppendChar(&out, 0); |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
|
927
|
0
|
0
|
|
|
|
|
if (err == PS_SUCCESS) |
928
|
|
|
|
|
|
|
{ |
929
|
0
|
|
|
|
|
|
*output = psDynBufDetach(&out, output_len); |
930
|
0
|
0
|
|
|
|
|
*output_len -= (opts & PS_STRING_DUAL_NIL) ? 2 : 1; |
931
|
0
|
0
|
|
|
|
|
if (*output == NULL) |
932
|
|
|
|
|
|
|
{ |
933
|
0
|
|
|
|
|
|
return PS_MEM_FAIL; |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
} |
936
|
|
|
|
|
|
|
else |
937
|
|
|
|
|
|
|
{ |
938
|
0
|
|
|
|
|
|
psDynBufUninit(&out); |
939
|
|
|
|
|
|
|
} |
940
|
0
|
|
|
|
|
|
return err; |
941
|
|
|
|
|
|
|
} |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
/******************************************************************************/ |
944
|
|
|
|
|
|
|
/* |
945
|
|
|
|
|
|
|
Support for memory allocation in order to avoid applications that redefine |
946
|
|
|
|
|
|
|
malloc/free (see Perl) |
947
|
|
|
|
|
|
|
*/ |
948
|
2
|
|
|
|
|
|
void *psMallocNative(size_t size) |
949
|
|
|
|
|
|
|
{ |
950
|
2
|
|
|
|
|
|
return malloc(size); |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
|
953
|
12
|
|
|
|
|
|
void psFreeNative(void *ptr) |
954
|
|
|
|
|
|
|
{ |
955
|
12
|
|
|
|
|
|
free(ptr); |
956
|
12
|
|
|
|
|
|
} |