1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 
12 /**
13   @file der_decode_generalizedtime.c
14   ASN.1 DER, decode a GeneralizedTime, Steffen Jaeckel
15   Based on der_decode_utctime.c
16 */
17 
18 #ifdef LTC_DER
19 
_char_to_int(unsigned char x)20 static int _char_to_int(unsigned char x)
21 {
22    switch (x)  {
23       case '0': return 0;
24       case '1': return 1;
25       case '2': return 2;
26       case '3': return 3;
27       case '4': return 4;
28       case '5': return 5;
29       case '6': return 6;
30       case '7': return 7;
31       case '8': return 8;
32       case '9': return 9;
33       default:  return 100;
34    }
35 }
36 
37 #define DECODE_V(y, max) do {\
38    y  = _char_to_int(buf[x])*10 + _char_to_int(buf[x+1]); \
39    if (y >= max) return CRYPT_INVALID_PACKET;           \
40    x += 2; \
41 } while(0)
42 
43 #define DECODE_V4(y, max) do {\
44    y  = _char_to_int(buf[x])*1000 + _char_to_int(buf[x+1])*100 + _char_to_int(buf[x+2])*10 + _char_to_int(buf[x+3]); \
45    if (y >= max) return CRYPT_INVALID_PACKET; \
46    x += 4; \
47 } while(0)
48 
49 /**
50   Decodes a Generalized time structure in DER format (reads all 6 valid encoding formats)
51   @param in     Input buffer
52   @param inlen  Length of input buffer in octets
53   @param out    [out] Destination of Generalized time structure
54   @return CRYPT_OK   if successful
55 */
der_decode_generalizedtime(const unsigned char * in,unsigned long * inlen,ltc_generalizedtime * out)56 int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
57                                ltc_generalizedtime *out)
58 {
59    unsigned char buf[32];
60    unsigned long x;
61    int           y;
62 
63    LTC_ARGCHK(in    != NULL);
64    LTC_ARGCHK(inlen != NULL);
65    LTC_ARGCHK(out   != NULL);
66 
67    /* check header */
68    if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
69       return CRYPT_INVALID_PACKET;
70    }
71 
72    /* decode the string */
73    for (x = 0; x < in[1]; x++) {
74        y = der_ia5_value_decode(in[x+2]);
75        if (y == -1) {
76           return CRYPT_INVALID_PACKET;
77        }
78        if (!((y >= '0' && y <= '9')
79             || y == 'Z' || y == '.'
80             || y == '+' || y == '-')) {
81           return CRYPT_INVALID_PACKET;
82        }
83        buf[x] = y;
84    }
85    *inlen = 2 + x;
86 
87    if (x < 15) {
88       return CRYPT_INVALID_PACKET;
89    }
90 
91    /* possible encodings are
92 YYYYMMDDhhmmssZ
93 YYYYMMDDhhmmss+hh'mm'
94 YYYYMMDDhhmmss-hh'mm'
95 YYYYMMDDhhmmss.fsZ
96 YYYYMMDDhhmmss.fs+hh'mm'
97 YYYYMMDDhhmmss.fs-hh'mm'
98 
99     So let's do a trivial decode upto [including] ss
100    */
101 
102     x = 0;
103     DECODE_V4(out->YYYY, 10000);
104     DECODE_V(out->MM, 13);
105     DECODE_V(out->DD, 32);
106     DECODE_V(out->hh, 24);
107     DECODE_V(out->mm, 60);
108     DECODE_V(out->ss, 60);
109 
110     /* clear fractional seconds info */
111     out->fs = 0;
112 
113     /* now is it Z or . */
114     if (buf[x] == 'Z') {
115        return CRYPT_OK;
116     }
117     if (buf[x] == '.') {
118        x++;
119        while (buf[x] >= '0' && buf[x] <= '9') {
120           unsigned fs = out->fs;
121           if (x >= sizeof(buf)) return CRYPT_INVALID_PACKET;
122           out->fs *= 10;
123           out->fs += _char_to_int(buf[x]);
124           if (fs > out->fs) return CRYPT_OVERFLOW;
125           x++;
126        }
127     }
128 
129     /* now is it Z, +, - */
130     if (buf[x] == 'Z') {
131        return CRYPT_OK;
132     }
133     if (buf[x] == '+' || buf[x] == '-') {
134        out->off_dir = (buf[x++] == '+') ? 0 : 1;
135        DECODE_V(out->off_hh, 24);
136        DECODE_V(out->off_mm, 60);
137        return CRYPT_OK;
138     }
139     return CRYPT_INVALID_PACKET;
140 }
141 
142 #endif
143 
144 /* ref:         $Format:%D$ */
145 /* git commit:  $Format:%H$ */
146 /* commit time: $Format:%ai$ */
147