File Coverage

inc/matrixssl-3-9-3-open/core/corelib.c
Criterion Covered Total %
statement 175 318 55.0
branch 77 200 38.5
condition n/a
subroutine n/a
pod n/a
total 252 518 48.6


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 17106594           void psBurnStack(uint32 len)
356             {
357             unsigned char buf[32];
358              
359 17106594           memset_s(buf, sizeof(buf), 0x0, sizeof(buf));
360 17106594 100         if (len > (uint32) sizeof(buf))
361             {
362 12190371           psBurnStack(len - sizeof(buf));
363             }
364 17106594           }
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           }