5a4b1742f7391bd4108db49a1569685fbc60e860
[openssl.git] / crypto / asn1 / a_utctm.c
1 /*
2  * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdio.h>
11 #include <time.h>
12 #include "internal/cryptlib.h"
13 #include <openssl/asn1.h>
14 #include "asn1_locl.h"
15
16 int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
17 {
18     static const int min[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };
19     static const int max[8] = { 99, 12, 31, 23, 59, 59, 12, 59 };
20     char *a;
21     int n, i, l, o, min_l = 11, strict = 0;
22
23     if (d->type != V_ASN1_UTCTIME)
24         return 0;
25     l = d->length;
26     a = (char *)d->data;
27     o = 0;
28
29     /*
30      * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280
31      * time string format, in which:
32      *
33      * 1. "seconds" is a 'MUST'
34      * 2. "Zulu" timezone is a 'MUST'
35      * 3. "+|-" is not allowed to indicate a time zone
36      */
37
38     if (d->flags & ASN1_STRING_FLAG_X509_TIME) {
39         min_l = 13;
40         strict = 1;
41     }
42
43     if (l < min_l)
44         goto err;
45     for (i = 0; i < 6; i++) {
46         if (!strict && (i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
47             i++;
48             if (tm)
49                 tm->tm_sec = 0;
50             break;
51         }
52         if ((a[o] < '0') || (a[o] > '9'))
53             goto err;
54         n = a[o] - '0';
55         /* incomplete 2-digital number */
56         if (++o == l)
57             goto err;
58
59         if ((a[o] < '0') || (a[o] > '9'))
60             goto err;
61         n = (n * 10) + a[o] - '0';
62         /* no more bytes to read, but we haven't seen time-zone yet */
63         if (++o == l)
64             goto err;
65
66         if ((n < min[i]) || (n > max[i]))
67             goto err;
68         if (tm) {
69             switch (i) {
70             case 0:
71                 tm->tm_year = n < 50 ? n + 100 : n;
72                 break;
73             case 1:
74                 tm->tm_mon = n - 1;
75                 break;
76             case 2:
77                 tm->tm_mday = n;
78                 break;
79             case 3:
80                 tm->tm_hour = n;
81                 break;
82             case 4:
83                 tm->tm_min = n;
84                 break;
85             case 5:
86                 tm->tm_sec = n;
87                 break;
88             }
89         }
90     }
91
92     /*
93      * 'o' will never point to '\0' at this point, the only chance
94      * 'o' can point th '\0' is either the subsequent if or the first
95      * else if is true.
96      */
97     if (a[o] == 'Z') {
98         o++;
99     } else if (!strict && ((a[o] == '+') || (a[o] == '-'))) {
100         int offsign = a[o] == '-' ? 1 : -1, offset = 0;
101         o++;
102         if (o + 4 != l)
103             goto err;
104         for (i = 6; i < 8; i++) {
105             if ((a[o] < '0') || (a[o] > '9'))
106                 goto err;
107             n = a[o] - '0';
108             o++;
109             if ((a[o] < '0') || (a[o] > '9'))
110                 goto err;
111             n = (n * 10) + a[o] - '0';
112             if ((n < min[i]) || (n > max[i]))
113                 goto err;
114             if (tm) {
115                 if (i == 6)
116                     offset = n * 3600;
117                 else if (i == 7)
118                     offset += n * 60;
119             }
120             o++;
121         }
122         if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
123             return 0;
124     } else {
125         /* not Z, or not +/- in non-strict mode */
126         return 0;
127     }
128     return o == l;
129  err:
130     return 0;
131 }
132
133 int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
134 {
135     return asn1_utctime_to_tm(NULL, d);
136 }
137
138 int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
139 {
140     ASN1_UTCTIME t;
141
142     t.type = V_ASN1_UTCTIME;
143     t.length = strlen(str);
144     t.data = (unsigned char *)str;
145     t.flags = 0;
146
147     if (ASN1_UTCTIME_check(&t)) {
148         if (s != NULL) {
149             if (!ASN1_STRING_set((ASN1_STRING *)s, str, t.length))
150                 return 0;
151             s->type = V_ASN1_UTCTIME;
152         }
153         return 1;
154     }
155     return 0;
156 }
157
158 ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
159 {
160     return ASN1_UTCTIME_adj(s, t, 0, 0);
161 }
162
163 ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
164                                int offset_day, long offset_sec)
165 {
166     char *p;
167     struct tm *ts;
168     struct tm data;
169     const size_t len = 20;
170     int free_s = 0;
171
172     if (s == NULL) {
173         s = ASN1_UTCTIME_new();
174         if (s == NULL)
175             goto err;
176         free_s = 1;
177     }
178
179     ts = OPENSSL_gmtime(&t, &data);
180     if (ts == NULL)
181         goto err;
182
183     if (offset_day || offset_sec) {
184         if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
185             goto err;
186     }
187
188     if ((ts->tm_year < 50) || (ts->tm_year >= 150))
189         goto err;
190
191     p = (char *)s->data;
192     if ((p == NULL) || ((size_t)s->length < len)) {
193         p = OPENSSL_malloc(len);
194         if (p == NULL) {
195             ASN1err(ASN1_F_ASN1_UTCTIME_ADJ, ERR_R_MALLOC_FAILURE);
196             goto err;
197         }
198         OPENSSL_free(s->data);
199         s->data = (unsigned char *)p;
200     }
201
202     s->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ",
203                              ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday,
204                              ts->tm_hour, ts->tm_min, ts->tm_sec);
205     s->type = V_ASN1_UTCTIME;
206 #ifdef CHARSET_EBCDIC_not
207     ebcdic2ascii(s->data, s->data, s->length);
208 #endif
209     return s;
210  err:
211     if (free_s)
212         ASN1_UTCTIME_free(s);
213     return NULL;
214 }
215
216 int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
217 {
218     struct tm stm, ttm;
219     int day, sec;
220
221     if (!asn1_utctime_to_tm(&stm, s))
222         return -2;
223
224     if (!OPENSSL_gmtime(&t, &ttm))
225         return -2;
226
227     if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm))
228         return -2;
229
230     if (day > 0)
231         return 1;
232     if (day < 0)
233         return -1;
234     if (sec > 0)
235         return 1;
236     if (sec < 0)
237         return -1;
238     return 0;
239 }
240
241 int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
242 {
243     const char *v;
244     int gmt = 0;
245     int i;
246     int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
247
248     i = tm->length;
249     v = (const char *)tm->data;
250
251     if (i < 10)
252         goto err;
253     if (v[i - 1] == 'Z')
254         gmt = 1;
255     for (i = 0; i < 10; i++)
256         if ((v[i] > '9') || (v[i] < '0'))
257             goto err;
258     y = (v[0] - '0') * 10 + (v[1] - '0');
259     if (y < 50)
260         y += 100;
261     M = (v[2] - '0') * 10 + (v[3] - '0');
262     if ((M > 12) || (M < 1))
263         goto err;
264     d = (v[4] - '0') * 10 + (v[5] - '0');
265     h = (v[6] - '0') * 10 + (v[7] - '0');
266     m = (v[8] - '0') * 10 + (v[9] - '0');
267     if (tm->length >= 12 &&
268         (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9'))
269         s = (v[10] - '0') * 10 + (v[11] - '0');
270
271     if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
272                    _asn1_mon[M - 1], d, h, m, s, y + 1900,
273                    (gmt) ? " GMT" : "") <= 0)
274         return 0;
275     return 1;
276  err:
277     BIO_write(bp, "Bad time value", 14);
278     return 0;
279 }