Introduce ASN1_TIME_set_string_X509 API
[openssl.git] / crypto / asn1 / a_utctm.c
1 /*
2  * Copyright 1995-2016 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     } else
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     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     BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ", ts->tm_year % 100,
203                  ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
204                  ts->tm_sec);
205     s->length = strlen(p);
206     s->type = V_ASN1_UTCTIME;
207 #ifdef CHARSET_EBCDIC_not
208     ebcdic2ascii(s->data, s->data, s->length);
209 #endif
210     return (s);
211  err:
212     if (free_s)
213         ASN1_UTCTIME_free(s);
214     return NULL;
215 }
216
217 int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
218 {
219     struct tm stm, ttm;
220     int day, sec;
221
222     if (!asn1_utctime_to_tm(&stm, s))
223         return -2;
224
225     if (!OPENSSL_gmtime(&t, &ttm))
226         return -2;
227
228     if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm))
229         return -2;
230
231     if (day > 0)
232         return 1;
233     if (day < 0)
234         return -1;
235     if (sec > 0)
236         return 1;
237     if (sec < 0)
238         return -1;
239     return 0;
240 }
241
242 int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
243 {
244     const char *v;
245     int gmt = 0;
246     int i;
247     int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
248
249     i = tm->length;
250     v = (const char *)tm->data;
251
252     if (i < 10)
253         goto err;
254     if (v[i - 1] == 'Z')
255         gmt = 1;
256     for (i = 0; i < 10; i++)
257         if ((v[i] > '9') || (v[i] < '0'))
258             goto err;
259     y = (v[0] - '0') * 10 + (v[1] - '0');
260     if (y < 50)
261         y += 100;
262     M = (v[2] - '0') * 10 + (v[3] - '0');
263     if ((M > 12) || (M < 1))
264         goto err;
265     d = (v[4] - '0') * 10 + (v[5] - '0');
266     h = (v[6] - '0') * 10 + (v[7] - '0');
267     m = (v[8] - '0') * 10 + (v[9] - '0');
268     if (tm->length >= 12 &&
269         (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9'))
270         s = (v[10] - '0') * 10 + (v[11] - '0');
271
272     if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
273                    _asn1_mon[M - 1], d, h, m, s, y + 1900,
274                    (gmt) ? " GMT" : "") <= 0)
275         return (0);
276     else
277         return (1);
278  err:
279     BIO_write(bp, "Bad time value", 14);
280     return (0);
281 }