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