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