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