Add asn1_time_to_tm function and check days in month
[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     /* wrapper around ans1_time_to_tm */
19     if (d->type != V_ASN1_UTCTIME)
20         return 0;
21     return asn1_time_to_tm(tm, d);
22 }
23
24 int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
25 {
26     return asn1_utctime_to_tm(NULL, d);
27 }
28
29 int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
30 {
31     ASN1_UTCTIME t;
32
33     t.type = V_ASN1_UTCTIME;
34     t.length = strlen(str);
35     t.data = (unsigned char *)str;
36     t.flags = 0;
37
38     if (ASN1_UTCTIME_check(&t)) {
39         if (s != NULL) {
40             if (!ASN1_STRING_set((ASN1_STRING *)s, str, t.length))
41                 return 0;
42             s->type = V_ASN1_UTCTIME;
43         }
44         return 1;
45     }
46     return 0;
47 }
48
49 ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
50 {
51     return ASN1_UTCTIME_adj(s, t, 0, 0);
52 }
53
54 ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
55                                int offset_day, long offset_sec)
56 {
57     char *p;
58     struct tm *ts;
59     struct tm data;
60     const size_t len = 20;
61     int free_s = 0;
62
63     if (s == NULL) {
64         s = ASN1_UTCTIME_new();
65         if (s == NULL)
66             goto err;
67         free_s = 1;
68     }
69
70     ts = OPENSSL_gmtime(&t, &data);
71     if (ts == NULL)
72         goto err;
73
74     if (offset_day || offset_sec) {
75         if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
76             goto err;
77     }
78
79     if ((ts->tm_year < 50) || (ts->tm_year >= 150))
80         goto err;
81
82     p = (char *)s->data;
83     if ((p == NULL) || ((size_t)s->length < len)) {
84         p = OPENSSL_malloc(len);
85         if (p == NULL) {
86             ASN1err(ASN1_F_ASN1_UTCTIME_ADJ, ERR_R_MALLOC_FAILURE);
87             goto err;
88         }
89         OPENSSL_free(s->data);
90         s->data = (unsigned char *)p;
91     }
92
93     s->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ",
94                              ts->tm_year % 100, ts->tm_mon + 1, ts->tm_mday,
95                              ts->tm_hour, ts->tm_min, ts->tm_sec);
96     s->type = V_ASN1_UTCTIME;
97 #ifdef CHARSET_EBCDIC_not
98     ebcdic2ascii(s->data, s->data, s->length);
99 #endif
100     return s;
101  err:
102     if (free_s)
103         ASN1_UTCTIME_free(s);
104     return NULL;
105 }
106
107 int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
108 {
109     struct tm stm, ttm;
110     int day, sec;
111
112     if (!asn1_utctime_to_tm(&stm, s))
113         return -2;
114
115     if (!OPENSSL_gmtime(&t, &ttm))
116         return -2;
117
118     if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm))
119         return -2;
120
121     if (day > 0)
122         return 1;
123     if (day < 0)
124         return -1;
125     if (sec > 0)
126         return 1;
127     if (sec < 0)
128         return -1;
129     return 0;
130 }
131
132 int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
133 {
134     const char *v;
135     int gmt = 0;
136     int i;
137     int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
138
139     i = tm->length;
140     v = (const char *)tm->data;
141
142     if (i < 10)
143         goto err;
144     if (v[i - 1] == 'Z')
145         gmt = 1;
146     for (i = 0; i < 10; i++)
147         if ((v[i] > '9') || (v[i] < '0'))
148             goto err;
149     y = (v[0] - '0') * 10 + (v[1] - '0');
150     if (y < 50)
151         y += 100;
152     M = (v[2] - '0') * 10 + (v[3] - '0');
153     if ((M > 12) || (M < 1))
154         goto err;
155     d = (v[4] - '0') * 10 + (v[5] - '0');
156     h = (v[6] - '0') * 10 + (v[7] - '0');
157     m = (v[8] - '0') * 10 + (v[9] - '0');
158     if (tm->length >= 12 &&
159         (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9'))
160         s = (v[10] - '0') * 10 + (v[11] - '0');
161
162     if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
163                    _asn1_mon[M - 1], d, h, m, s, y + 1900,
164                    (gmt) ? " GMT" : "") <= 0)
165         return 0;
166     return 1;
167  err:
168     BIO_write(bp, "Bad time value", 14);
169     return 0;
170 }