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