1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci/*- 11e1051a39Sopenharmony_ci * This is an implementation of the ASN1 Time structure which is: 12e1051a39Sopenharmony_ci * Time ::= CHOICE { 13e1051a39Sopenharmony_ci * utcTime UTCTime, 14e1051a39Sopenharmony_ci * generalTime GeneralizedTime } 15e1051a39Sopenharmony_ci */ 16e1051a39Sopenharmony_ci 17e1051a39Sopenharmony_ci#include <stdio.h> 18e1051a39Sopenharmony_ci#include <time.h> 19e1051a39Sopenharmony_ci#include "crypto/asn1.h" 20e1051a39Sopenharmony_ci#include "crypto/ctype.h" 21e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 22e1051a39Sopenharmony_ci#include <openssl/asn1t.h> 23e1051a39Sopenharmony_ci#include "asn1_local.h" 24e1051a39Sopenharmony_ci 25e1051a39Sopenharmony_ciIMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME) 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_ciIMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME) 28e1051a39Sopenharmony_ciIMPLEMENT_ASN1_DUP_FUNCTION(ASN1_TIME) 29e1051a39Sopenharmony_ci 30e1051a39Sopenharmony_cistatic int is_utc(const int year) 31e1051a39Sopenharmony_ci{ 32e1051a39Sopenharmony_ci if (50 <= year && year <= 149) 33e1051a39Sopenharmony_ci return 1; 34e1051a39Sopenharmony_ci return 0; 35e1051a39Sopenharmony_ci} 36e1051a39Sopenharmony_ci 37e1051a39Sopenharmony_cistatic int leap_year(const int year) 38e1051a39Sopenharmony_ci{ 39e1051a39Sopenharmony_ci if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) 40e1051a39Sopenharmony_ci return 1; 41e1051a39Sopenharmony_ci return 0; 42e1051a39Sopenharmony_ci} 43e1051a39Sopenharmony_ci 44e1051a39Sopenharmony_ci/* 45e1051a39Sopenharmony_ci * Compute the day of the week and the day of the year from the year, month 46e1051a39Sopenharmony_ci * and day. The day of the year is straightforward, the day of the week uses 47e1051a39Sopenharmony_ci * a form of Zeller's congruence. For this months start with March and are 48e1051a39Sopenharmony_ci * numbered 4 through 15. 49e1051a39Sopenharmony_ci */ 50e1051a39Sopenharmony_cistatic void determine_days(struct tm *tm) 51e1051a39Sopenharmony_ci{ 52e1051a39Sopenharmony_ci static const int ydays[12] = { 53e1051a39Sopenharmony_ci 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 54e1051a39Sopenharmony_ci }; 55e1051a39Sopenharmony_ci int y = tm->tm_year + 1900; 56e1051a39Sopenharmony_ci int m = tm->tm_mon; 57e1051a39Sopenharmony_ci int d = tm->tm_mday; 58e1051a39Sopenharmony_ci int c; 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_ci tm->tm_yday = ydays[m] + d - 1; 61e1051a39Sopenharmony_ci if (m >= 2) { 62e1051a39Sopenharmony_ci /* March and onwards can be one day further into the year */ 63e1051a39Sopenharmony_ci tm->tm_yday += leap_year(y); 64e1051a39Sopenharmony_ci m += 2; 65e1051a39Sopenharmony_ci } else { 66e1051a39Sopenharmony_ci /* Treat January and February as part of the previous year */ 67e1051a39Sopenharmony_ci m += 14; 68e1051a39Sopenharmony_ci y--; 69e1051a39Sopenharmony_ci } 70e1051a39Sopenharmony_ci c = y / 100; 71e1051a39Sopenharmony_ci y %= 100; 72e1051a39Sopenharmony_ci /* Zeller's congruence */ 73e1051a39Sopenharmony_ci tm->tm_wday = (d + (13 * m) / 5 + y + y / 4 + c / 4 + 5 * c + 6) % 7; 74e1051a39Sopenharmony_ci} 75e1051a39Sopenharmony_ci 76e1051a39Sopenharmony_ciint ossl_asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d) 77e1051a39Sopenharmony_ci{ 78e1051a39Sopenharmony_ci static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 }; 79e1051a39Sopenharmony_ci static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 }; 80e1051a39Sopenharmony_ci static const int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 81e1051a39Sopenharmony_ci char *a; 82e1051a39Sopenharmony_ci int n, i, i2, l, o, min_l = 11, strict = 0, end = 6, btz = 5, md; 83e1051a39Sopenharmony_ci struct tm tmp; 84e1051a39Sopenharmony_ci#if defined(CHARSET_EBCDIC) 85e1051a39Sopenharmony_ci const char upper_z = 0x5A, num_zero = 0x30, period = 0x2E, minus = 0x2D, plus = 0x2B; 86e1051a39Sopenharmony_ci#else 87e1051a39Sopenharmony_ci const char upper_z = 'Z', num_zero = '0', period = '.', minus = '-', plus = '+'; 88e1051a39Sopenharmony_ci#endif 89e1051a39Sopenharmony_ci /* 90e1051a39Sopenharmony_ci * ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280 91e1051a39Sopenharmony_ci * time string format, in which: 92e1051a39Sopenharmony_ci * 93e1051a39Sopenharmony_ci * 1. "seconds" is a 'MUST' 94e1051a39Sopenharmony_ci * 2. "Zulu" timezone is a 'MUST' 95e1051a39Sopenharmony_ci * 3. "+|-" is not allowed to indicate a time zone 96e1051a39Sopenharmony_ci */ 97e1051a39Sopenharmony_ci if (d->type == V_ASN1_UTCTIME) { 98e1051a39Sopenharmony_ci if (d->flags & ASN1_STRING_FLAG_X509_TIME) { 99e1051a39Sopenharmony_ci min_l = 13; 100e1051a39Sopenharmony_ci strict = 1; 101e1051a39Sopenharmony_ci } 102e1051a39Sopenharmony_ci } else if (d->type == V_ASN1_GENERALIZEDTIME) { 103e1051a39Sopenharmony_ci end = 7; 104e1051a39Sopenharmony_ci btz = 6; 105e1051a39Sopenharmony_ci if (d->flags & ASN1_STRING_FLAG_X509_TIME) { 106e1051a39Sopenharmony_ci min_l = 15; 107e1051a39Sopenharmony_ci strict = 1; 108e1051a39Sopenharmony_ci } else { 109e1051a39Sopenharmony_ci min_l = 13; 110e1051a39Sopenharmony_ci } 111e1051a39Sopenharmony_ci } else { 112e1051a39Sopenharmony_ci return 0; 113e1051a39Sopenharmony_ci } 114e1051a39Sopenharmony_ci 115e1051a39Sopenharmony_ci l = d->length; 116e1051a39Sopenharmony_ci a = (char *)d->data; 117e1051a39Sopenharmony_ci o = 0; 118e1051a39Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 119e1051a39Sopenharmony_ci 120e1051a39Sopenharmony_ci /* 121e1051a39Sopenharmony_ci * GENERALIZEDTIME is similar to UTCTIME except the year is represented 122e1051a39Sopenharmony_ci * as YYYY. This stuff treats everything as a two digit field so make 123e1051a39Sopenharmony_ci * first two fields 00 to 99 124e1051a39Sopenharmony_ci */ 125e1051a39Sopenharmony_ci 126e1051a39Sopenharmony_ci if (l < min_l) 127e1051a39Sopenharmony_ci goto err; 128e1051a39Sopenharmony_ci for (i = 0; i < end; i++) { 129e1051a39Sopenharmony_ci if (!strict && (i == btz) && ((a[o] == upper_z) || (a[o] == plus) || (a[o] == minus))) { 130e1051a39Sopenharmony_ci i++; 131e1051a39Sopenharmony_ci break; 132e1051a39Sopenharmony_ci } 133e1051a39Sopenharmony_ci if (!ossl_ascii_isdigit(a[o])) 134e1051a39Sopenharmony_ci goto err; 135e1051a39Sopenharmony_ci n = a[o] - num_zero; 136e1051a39Sopenharmony_ci /* incomplete 2-digital number */ 137e1051a39Sopenharmony_ci if (++o == l) 138e1051a39Sopenharmony_ci goto err; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci if (!ossl_ascii_isdigit(a[o])) 141e1051a39Sopenharmony_ci goto err; 142e1051a39Sopenharmony_ci n = (n * 10) + a[o] - num_zero; 143e1051a39Sopenharmony_ci /* no more bytes to read, but we haven't seen time-zone yet */ 144e1051a39Sopenharmony_ci if (++o == l) 145e1051a39Sopenharmony_ci goto err; 146e1051a39Sopenharmony_ci 147e1051a39Sopenharmony_ci i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i; 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci if ((n < min[i2]) || (n > max[i2])) 150e1051a39Sopenharmony_ci goto err; 151e1051a39Sopenharmony_ci switch (i2) { 152e1051a39Sopenharmony_ci case 0: 153e1051a39Sopenharmony_ci /* UTC will never be here */ 154e1051a39Sopenharmony_ci tmp.tm_year = n * 100 - 1900; 155e1051a39Sopenharmony_ci break; 156e1051a39Sopenharmony_ci case 1: 157e1051a39Sopenharmony_ci if (d->type == V_ASN1_UTCTIME) 158e1051a39Sopenharmony_ci tmp.tm_year = n < 50 ? n + 100 : n; 159e1051a39Sopenharmony_ci else 160e1051a39Sopenharmony_ci tmp.tm_year += n; 161e1051a39Sopenharmony_ci break; 162e1051a39Sopenharmony_ci case 2: 163e1051a39Sopenharmony_ci tmp.tm_mon = n - 1; 164e1051a39Sopenharmony_ci break; 165e1051a39Sopenharmony_ci case 3: 166e1051a39Sopenharmony_ci /* check if tm_mday is valid in tm_mon */ 167e1051a39Sopenharmony_ci if (tmp.tm_mon == 1) { 168e1051a39Sopenharmony_ci /* it's February */ 169e1051a39Sopenharmony_ci md = mdays[1] + leap_year(tmp.tm_year + 1900); 170e1051a39Sopenharmony_ci } else { 171e1051a39Sopenharmony_ci md = mdays[tmp.tm_mon]; 172e1051a39Sopenharmony_ci } 173e1051a39Sopenharmony_ci if (n > md) 174e1051a39Sopenharmony_ci goto err; 175e1051a39Sopenharmony_ci tmp.tm_mday = n; 176e1051a39Sopenharmony_ci determine_days(&tmp); 177e1051a39Sopenharmony_ci break; 178e1051a39Sopenharmony_ci case 4: 179e1051a39Sopenharmony_ci tmp.tm_hour = n; 180e1051a39Sopenharmony_ci break; 181e1051a39Sopenharmony_ci case 5: 182e1051a39Sopenharmony_ci tmp.tm_min = n; 183e1051a39Sopenharmony_ci break; 184e1051a39Sopenharmony_ci case 6: 185e1051a39Sopenharmony_ci tmp.tm_sec = n; 186e1051a39Sopenharmony_ci break; 187e1051a39Sopenharmony_ci } 188e1051a39Sopenharmony_ci } 189e1051a39Sopenharmony_ci 190e1051a39Sopenharmony_ci /* 191e1051a39Sopenharmony_ci * Optional fractional seconds: decimal point followed by one or more 192e1051a39Sopenharmony_ci * digits. 193e1051a39Sopenharmony_ci */ 194e1051a39Sopenharmony_ci if (d->type == V_ASN1_GENERALIZEDTIME && a[o] == period) { 195e1051a39Sopenharmony_ci if (strict) 196e1051a39Sopenharmony_ci /* RFC 5280 forbids fractional seconds */ 197e1051a39Sopenharmony_ci goto err; 198e1051a39Sopenharmony_ci if (++o == l) 199e1051a39Sopenharmony_ci goto err; 200e1051a39Sopenharmony_ci i = o; 201e1051a39Sopenharmony_ci while ((o < l) && ossl_ascii_isdigit(a[o])) 202e1051a39Sopenharmony_ci o++; 203e1051a39Sopenharmony_ci /* Must have at least one digit after decimal point */ 204e1051a39Sopenharmony_ci if (i == o) 205e1051a39Sopenharmony_ci goto err; 206e1051a39Sopenharmony_ci /* no more bytes to read, but we haven't seen time-zone yet */ 207e1051a39Sopenharmony_ci if (o == l) 208e1051a39Sopenharmony_ci goto err; 209e1051a39Sopenharmony_ci } 210e1051a39Sopenharmony_ci 211e1051a39Sopenharmony_ci /* 212e1051a39Sopenharmony_ci * 'o' will never point to '\0' at this point, the only chance 213e1051a39Sopenharmony_ci * 'o' can point to '\0' is either the subsequent if or the first 214e1051a39Sopenharmony_ci * else if is true. 215e1051a39Sopenharmony_ci */ 216e1051a39Sopenharmony_ci if (a[o] == upper_z) { 217e1051a39Sopenharmony_ci o++; 218e1051a39Sopenharmony_ci } else if (!strict && ((a[o] == plus) || (a[o] == minus))) { 219e1051a39Sopenharmony_ci int offsign = a[o] == minus ? 1 : -1; 220e1051a39Sopenharmony_ci int offset = 0; 221e1051a39Sopenharmony_ci 222e1051a39Sopenharmony_ci o++; 223e1051a39Sopenharmony_ci /* 224e1051a39Sopenharmony_ci * if not equal, no need to do subsequent checks 225e1051a39Sopenharmony_ci * since the following for-loop will add 'o' by 4 226e1051a39Sopenharmony_ci * and the final return statement will check if 'l' 227e1051a39Sopenharmony_ci * and 'o' are equal. 228e1051a39Sopenharmony_ci */ 229e1051a39Sopenharmony_ci if (o + 4 != l) 230e1051a39Sopenharmony_ci goto err; 231e1051a39Sopenharmony_ci for (i = end; i < end + 2; i++) { 232e1051a39Sopenharmony_ci if (!ossl_ascii_isdigit(a[o])) 233e1051a39Sopenharmony_ci goto err; 234e1051a39Sopenharmony_ci n = a[o] - num_zero; 235e1051a39Sopenharmony_ci o++; 236e1051a39Sopenharmony_ci if (!ossl_ascii_isdigit(a[o])) 237e1051a39Sopenharmony_ci goto err; 238e1051a39Sopenharmony_ci n = (n * 10) + a[o] - num_zero; 239e1051a39Sopenharmony_ci i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i; 240e1051a39Sopenharmony_ci if ((n < min[i2]) || (n > max[i2])) 241e1051a39Sopenharmony_ci goto err; 242e1051a39Sopenharmony_ci /* if tm is NULL, no need to adjust */ 243e1051a39Sopenharmony_ci if (tm != NULL) { 244e1051a39Sopenharmony_ci if (i == end) 245e1051a39Sopenharmony_ci offset = n * 3600; 246e1051a39Sopenharmony_ci else if (i == end + 1) 247e1051a39Sopenharmony_ci offset += n * 60; 248e1051a39Sopenharmony_ci } 249e1051a39Sopenharmony_ci o++; 250e1051a39Sopenharmony_ci } 251e1051a39Sopenharmony_ci if (offset && !OPENSSL_gmtime_adj(&tmp, 0, offset * offsign)) 252e1051a39Sopenharmony_ci goto err; 253e1051a39Sopenharmony_ci } else { 254e1051a39Sopenharmony_ci /* not Z, or not +/- in non-strict mode */ 255e1051a39Sopenharmony_ci goto err; 256e1051a39Sopenharmony_ci } 257e1051a39Sopenharmony_ci if (o == l) { 258e1051a39Sopenharmony_ci /* success, check if tm should be filled */ 259e1051a39Sopenharmony_ci if (tm != NULL) 260e1051a39Sopenharmony_ci *tm = tmp; 261e1051a39Sopenharmony_ci return 1; 262e1051a39Sopenharmony_ci } 263e1051a39Sopenharmony_ci err: 264e1051a39Sopenharmony_ci return 0; 265e1051a39Sopenharmony_ci} 266e1051a39Sopenharmony_ci 267e1051a39Sopenharmony_ciASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type) 268e1051a39Sopenharmony_ci{ 269e1051a39Sopenharmony_ci char* p; 270e1051a39Sopenharmony_ci ASN1_TIME *tmps = NULL; 271e1051a39Sopenharmony_ci const size_t len = 20; 272e1051a39Sopenharmony_ci 273e1051a39Sopenharmony_ci if (type == V_ASN1_UNDEF) { 274e1051a39Sopenharmony_ci if (is_utc(ts->tm_year)) 275e1051a39Sopenharmony_ci type = V_ASN1_UTCTIME; 276e1051a39Sopenharmony_ci else 277e1051a39Sopenharmony_ci type = V_ASN1_GENERALIZEDTIME; 278e1051a39Sopenharmony_ci } else if (type == V_ASN1_UTCTIME) { 279e1051a39Sopenharmony_ci if (!is_utc(ts->tm_year)) 280e1051a39Sopenharmony_ci goto err; 281e1051a39Sopenharmony_ci } else if (type != V_ASN1_GENERALIZEDTIME) { 282e1051a39Sopenharmony_ci goto err; 283e1051a39Sopenharmony_ci } 284e1051a39Sopenharmony_ci 285e1051a39Sopenharmony_ci if (s == NULL) 286e1051a39Sopenharmony_ci tmps = ASN1_STRING_new(); 287e1051a39Sopenharmony_ci else 288e1051a39Sopenharmony_ci tmps = s; 289e1051a39Sopenharmony_ci if (tmps == NULL) 290e1051a39Sopenharmony_ci return NULL; 291e1051a39Sopenharmony_ci 292e1051a39Sopenharmony_ci if (!ASN1_STRING_set(tmps, NULL, len)) 293e1051a39Sopenharmony_ci goto err; 294e1051a39Sopenharmony_ci 295e1051a39Sopenharmony_ci tmps->type = type; 296e1051a39Sopenharmony_ci p = (char*)tmps->data; 297e1051a39Sopenharmony_ci 298e1051a39Sopenharmony_ci if (type == V_ASN1_GENERALIZEDTIME) 299e1051a39Sopenharmony_ci tmps->length = BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", 300e1051a39Sopenharmony_ci ts->tm_year + 1900, ts->tm_mon + 1, 301e1051a39Sopenharmony_ci ts->tm_mday, ts->tm_hour, ts->tm_min, 302e1051a39Sopenharmony_ci ts->tm_sec); 303e1051a39Sopenharmony_ci else 304e1051a39Sopenharmony_ci tmps->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ", 305e1051a39Sopenharmony_ci ts->tm_year % 100, ts->tm_mon + 1, 306e1051a39Sopenharmony_ci ts->tm_mday, ts->tm_hour, ts->tm_min, 307e1051a39Sopenharmony_ci ts->tm_sec); 308e1051a39Sopenharmony_ci 309e1051a39Sopenharmony_ci#ifdef CHARSET_EBCDIC 310e1051a39Sopenharmony_ci ebcdic2ascii(tmps->data, tmps->data, tmps->length); 311e1051a39Sopenharmony_ci#endif 312e1051a39Sopenharmony_ci return tmps; 313e1051a39Sopenharmony_ci err: 314e1051a39Sopenharmony_ci if (tmps != s) 315e1051a39Sopenharmony_ci ASN1_STRING_free(tmps); 316e1051a39Sopenharmony_ci return NULL; 317e1051a39Sopenharmony_ci} 318e1051a39Sopenharmony_ci 319e1051a39Sopenharmony_ciASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t) 320e1051a39Sopenharmony_ci{ 321e1051a39Sopenharmony_ci return ASN1_TIME_adj(s, t, 0, 0); 322e1051a39Sopenharmony_ci} 323e1051a39Sopenharmony_ci 324e1051a39Sopenharmony_ciASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, 325e1051a39Sopenharmony_ci int offset_day, long offset_sec) 326e1051a39Sopenharmony_ci{ 327e1051a39Sopenharmony_ci struct tm *ts; 328e1051a39Sopenharmony_ci struct tm data; 329e1051a39Sopenharmony_ci 330e1051a39Sopenharmony_ci ts = OPENSSL_gmtime(&t, &data); 331e1051a39Sopenharmony_ci if (ts == NULL) { 332e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME); 333e1051a39Sopenharmony_ci return NULL; 334e1051a39Sopenharmony_ci } 335e1051a39Sopenharmony_ci if (offset_day || offset_sec) { 336e1051a39Sopenharmony_ci if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) 337e1051a39Sopenharmony_ci return NULL; 338e1051a39Sopenharmony_ci } 339e1051a39Sopenharmony_ci return ossl_asn1_time_from_tm(s, ts, V_ASN1_UNDEF); 340e1051a39Sopenharmony_ci} 341e1051a39Sopenharmony_ci 342e1051a39Sopenharmony_ciint ASN1_TIME_check(const ASN1_TIME *t) 343e1051a39Sopenharmony_ci{ 344e1051a39Sopenharmony_ci if (t->type == V_ASN1_GENERALIZEDTIME) 345e1051a39Sopenharmony_ci return ASN1_GENERALIZEDTIME_check(t); 346e1051a39Sopenharmony_ci else if (t->type == V_ASN1_UTCTIME) 347e1051a39Sopenharmony_ci return ASN1_UTCTIME_check(t); 348e1051a39Sopenharmony_ci return 0; 349e1051a39Sopenharmony_ci} 350e1051a39Sopenharmony_ci 351e1051a39Sopenharmony_ci/* Convert an ASN1_TIME structure to GeneralizedTime */ 352e1051a39Sopenharmony_ciASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t, 353e1051a39Sopenharmony_ci ASN1_GENERALIZEDTIME **out) 354e1051a39Sopenharmony_ci{ 355e1051a39Sopenharmony_ci ASN1_GENERALIZEDTIME *ret = NULL; 356e1051a39Sopenharmony_ci struct tm tm; 357e1051a39Sopenharmony_ci 358e1051a39Sopenharmony_ci if (!ASN1_TIME_to_tm(t, &tm)) 359e1051a39Sopenharmony_ci return NULL; 360e1051a39Sopenharmony_ci 361e1051a39Sopenharmony_ci if (out != NULL) 362e1051a39Sopenharmony_ci ret = *out; 363e1051a39Sopenharmony_ci 364e1051a39Sopenharmony_ci ret = ossl_asn1_time_from_tm(ret, &tm, V_ASN1_GENERALIZEDTIME); 365e1051a39Sopenharmony_ci 366e1051a39Sopenharmony_ci if (out != NULL && ret != NULL) 367e1051a39Sopenharmony_ci *out = ret; 368e1051a39Sopenharmony_ci 369e1051a39Sopenharmony_ci return ret; 370e1051a39Sopenharmony_ci} 371e1051a39Sopenharmony_ci 372e1051a39Sopenharmony_ciint ASN1_TIME_set_string(ASN1_TIME *s, const char *str) 373e1051a39Sopenharmony_ci{ 374e1051a39Sopenharmony_ci /* Try UTC, if that fails, try GENERALIZED */ 375e1051a39Sopenharmony_ci if (ASN1_UTCTIME_set_string(s, str)) 376e1051a39Sopenharmony_ci return 1; 377e1051a39Sopenharmony_ci return ASN1_GENERALIZEDTIME_set_string(s, str); 378e1051a39Sopenharmony_ci} 379e1051a39Sopenharmony_ci 380e1051a39Sopenharmony_ciint ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str) 381e1051a39Sopenharmony_ci{ 382e1051a39Sopenharmony_ci ASN1_TIME t; 383e1051a39Sopenharmony_ci struct tm tm; 384e1051a39Sopenharmony_ci int rv = 0; 385e1051a39Sopenharmony_ci 386e1051a39Sopenharmony_ci t.length = strlen(str); 387e1051a39Sopenharmony_ci t.data = (unsigned char *)str; 388e1051a39Sopenharmony_ci t.flags = ASN1_STRING_FLAG_X509_TIME; 389e1051a39Sopenharmony_ci 390e1051a39Sopenharmony_ci t.type = V_ASN1_UTCTIME; 391e1051a39Sopenharmony_ci 392e1051a39Sopenharmony_ci if (!ASN1_TIME_check(&t)) { 393e1051a39Sopenharmony_ci t.type = V_ASN1_GENERALIZEDTIME; 394e1051a39Sopenharmony_ci if (!ASN1_TIME_check(&t)) 395e1051a39Sopenharmony_ci goto out; 396e1051a39Sopenharmony_ci } 397e1051a39Sopenharmony_ci 398e1051a39Sopenharmony_ci /* 399e1051a39Sopenharmony_ci * Per RFC 5280 (section 4.1.2.5.), the valid input time 400e1051a39Sopenharmony_ci * strings should be encoded with the following rules: 401e1051a39Sopenharmony_ci * 402e1051a39Sopenharmony_ci * 1. UTC: YYMMDDHHMMSSZ, if YY < 50 (20YY) --> UTC: YYMMDDHHMMSSZ 403e1051a39Sopenharmony_ci * 2. UTC: YYMMDDHHMMSSZ, if YY >= 50 (19YY) --> UTC: YYMMDDHHMMSSZ 404e1051a39Sopenharmony_ci * 3. G'd: YYYYMMDDHHMMSSZ, if YYYY >= 2050 --> G'd: YYYYMMDDHHMMSSZ 405e1051a39Sopenharmony_ci * 4. G'd: YYYYMMDDHHMMSSZ, if YYYY < 2050 --> UTC: YYMMDDHHMMSSZ 406e1051a39Sopenharmony_ci * 407e1051a39Sopenharmony_ci * Only strings of the 4th rule should be reformatted, but since a 408e1051a39Sopenharmony_ci * UTC can only present [1950, 2050), so if the given time string 409e1051a39Sopenharmony_ci * is less than 1950 (e.g. 19230419000000Z), we do nothing... 410e1051a39Sopenharmony_ci */ 411e1051a39Sopenharmony_ci 412e1051a39Sopenharmony_ci if (s != NULL && t.type == V_ASN1_GENERALIZEDTIME) { 413e1051a39Sopenharmony_ci if (!ossl_asn1_time_to_tm(&tm, &t)) 414e1051a39Sopenharmony_ci goto out; 415e1051a39Sopenharmony_ci if (is_utc(tm.tm_year)) { 416e1051a39Sopenharmony_ci t.length -= 2; 417e1051a39Sopenharmony_ci /* 418e1051a39Sopenharmony_ci * it's OK to let original t.data go since that's assigned 419e1051a39Sopenharmony_ci * to a piece of memory allocated outside of this function. 420e1051a39Sopenharmony_ci * new t.data would be freed after ASN1_STRING_copy is done. 421e1051a39Sopenharmony_ci */ 422e1051a39Sopenharmony_ci t.data = OPENSSL_zalloc(t.length + 1); 423e1051a39Sopenharmony_ci if (t.data == NULL) { 424e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); 425e1051a39Sopenharmony_ci goto out; 426e1051a39Sopenharmony_ci } 427e1051a39Sopenharmony_ci memcpy(t.data, str + 2, t.length); 428e1051a39Sopenharmony_ci t.type = V_ASN1_UTCTIME; 429e1051a39Sopenharmony_ci } 430e1051a39Sopenharmony_ci } 431e1051a39Sopenharmony_ci 432e1051a39Sopenharmony_ci if (s == NULL || ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t)) 433e1051a39Sopenharmony_ci rv = 1; 434e1051a39Sopenharmony_ci 435e1051a39Sopenharmony_ci if (t.data != (unsigned char *)str) 436e1051a39Sopenharmony_ci OPENSSL_free(t.data); 437e1051a39Sopenharmony_ciout: 438e1051a39Sopenharmony_ci return rv; 439e1051a39Sopenharmony_ci} 440e1051a39Sopenharmony_ci 441e1051a39Sopenharmony_ciint ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm) 442e1051a39Sopenharmony_ci{ 443e1051a39Sopenharmony_ci if (s == NULL) { 444e1051a39Sopenharmony_ci time_t now_t; 445e1051a39Sopenharmony_ci 446e1051a39Sopenharmony_ci time(&now_t); 447e1051a39Sopenharmony_ci memset(tm, 0, sizeof(*tm)); 448e1051a39Sopenharmony_ci if (OPENSSL_gmtime(&now_t, tm) != NULL) 449e1051a39Sopenharmony_ci return 1; 450e1051a39Sopenharmony_ci return 0; 451e1051a39Sopenharmony_ci } 452e1051a39Sopenharmony_ci 453e1051a39Sopenharmony_ci return ossl_asn1_time_to_tm(tm, s); 454e1051a39Sopenharmony_ci} 455e1051a39Sopenharmony_ci 456e1051a39Sopenharmony_ciint ASN1_TIME_diff(int *pday, int *psec, 457e1051a39Sopenharmony_ci const ASN1_TIME *from, const ASN1_TIME *to) 458e1051a39Sopenharmony_ci{ 459e1051a39Sopenharmony_ci struct tm tm_from, tm_to; 460e1051a39Sopenharmony_ci 461e1051a39Sopenharmony_ci if (!ASN1_TIME_to_tm(from, &tm_from)) 462e1051a39Sopenharmony_ci return 0; 463e1051a39Sopenharmony_ci if (!ASN1_TIME_to_tm(to, &tm_to)) 464e1051a39Sopenharmony_ci return 0; 465e1051a39Sopenharmony_ci return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to); 466e1051a39Sopenharmony_ci} 467e1051a39Sopenharmony_ci 468e1051a39Sopenharmony_cistatic const char _asn1_mon[12][4] = { 469e1051a39Sopenharmony_ci "Jan", "Feb", "Mar", "Apr", "May", "Jun", 470e1051a39Sopenharmony_ci "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 471e1051a39Sopenharmony_ci}; 472e1051a39Sopenharmony_ci 473e1051a39Sopenharmony_ci/* prints the time with the default date format (RFC 822) */ 474e1051a39Sopenharmony_ciint ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) 475e1051a39Sopenharmony_ci{ 476e1051a39Sopenharmony_ci return ASN1_TIME_print_ex(bp, tm, ASN1_DTFLGS_RFC822); 477e1051a39Sopenharmony_ci} 478e1051a39Sopenharmony_ci 479e1051a39Sopenharmony_ci/* returns 1 on success, 0 on BIO write error or parse failure */ 480e1051a39Sopenharmony_ciint ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags) 481e1051a39Sopenharmony_ci{ 482e1051a39Sopenharmony_ci return ossl_asn1_time_print_ex(bp, tm, flags) > 0; 483e1051a39Sopenharmony_ci} 484e1051a39Sopenharmony_ci 485e1051a39Sopenharmony_ci 486e1051a39Sopenharmony_ci/* prints the time with the date format of ISO 8601 */ 487e1051a39Sopenharmony_ci/* returns 0 on BIO write error, else -1 in case of parse failure, else 1 */ 488e1051a39Sopenharmony_ciint ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags) 489e1051a39Sopenharmony_ci{ 490e1051a39Sopenharmony_ci char *v; 491e1051a39Sopenharmony_ci int gmt = 0, l; 492e1051a39Sopenharmony_ci struct tm stm; 493e1051a39Sopenharmony_ci const char upper_z = 0x5A, period = 0x2E; 494e1051a39Sopenharmony_ci 495e1051a39Sopenharmony_ci /* ossl_asn1_time_to_tm will check the time type */ 496e1051a39Sopenharmony_ci if (!ossl_asn1_time_to_tm(&stm, tm)) 497e1051a39Sopenharmony_ci return BIO_write(bp, "Bad time value", 14) ? -1 : 0; 498e1051a39Sopenharmony_ci 499e1051a39Sopenharmony_ci l = tm->length; 500e1051a39Sopenharmony_ci v = (char *)tm->data; 501e1051a39Sopenharmony_ci if (v[l - 1] == upper_z) 502e1051a39Sopenharmony_ci gmt = 1; 503e1051a39Sopenharmony_ci 504e1051a39Sopenharmony_ci if (tm->type == V_ASN1_GENERALIZEDTIME) { 505e1051a39Sopenharmony_ci char *f = NULL; 506e1051a39Sopenharmony_ci int f_len = 0; 507e1051a39Sopenharmony_ci 508e1051a39Sopenharmony_ci /* 509e1051a39Sopenharmony_ci * Try to parse fractional seconds. '14' is the place of 510e1051a39Sopenharmony_ci * 'fraction point' in a GeneralizedTime string. 511e1051a39Sopenharmony_ci */ 512e1051a39Sopenharmony_ci if (tm->length > 15 && v[14] == period) { 513e1051a39Sopenharmony_ci f = &v[14]; 514e1051a39Sopenharmony_ci f_len = 1; 515e1051a39Sopenharmony_ci while (14 + f_len < l && ossl_ascii_isdigit(f[f_len])) 516e1051a39Sopenharmony_ci ++f_len; 517e1051a39Sopenharmony_ci } 518e1051a39Sopenharmony_ci 519e1051a39Sopenharmony_ci if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) { 520e1051a39Sopenharmony_ci return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d%.*s%s", 521e1051a39Sopenharmony_ci stm.tm_year + 1900, stm.tm_mon + 1, 522e1051a39Sopenharmony_ci stm.tm_mday, stm.tm_hour, 523e1051a39Sopenharmony_ci stm.tm_min, stm.tm_sec, f_len, f, 524e1051a39Sopenharmony_ci (gmt ? "Z" : "")) > 0; 525e1051a39Sopenharmony_ci } 526e1051a39Sopenharmony_ci else { 527e1051a39Sopenharmony_ci return BIO_printf(bp, "%s %2d %02d:%02d:%02d%.*s %d%s", 528e1051a39Sopenharmony_ci _asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour, 529e1051a39Sopenharmony_ci stm.tm_min, stm.tm_sec, f_len, f, stm.tm_year + 1900, 530e1051a39Sopenharmony_ci (gmt ? " GMT" : "")) > 0; 531e1051a39Sopenharmony_ci } 532e1051a39Sopenharmony_ci } else { 533e1051a39Sopenharmony_ci if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) { 534e1051a39Sopenharmony_ci return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d%s", 535e1051a39Sopenharmony_ci stm.tm_year + 1900, stm.tm_mon + 1, 536e1051a39Sopenharmony_ci stm.tm_mday, stm.tm_hour, 537e1051a39Sopenharmony_ci stm.tm_min, stm.tm_sec, 538e1051a39Sopenharmony_ci (gmt ? "Z" : "")) > 0; 539e1051a39Sopenharmony_ci } 540e1051a39Sopenharmony_ci else { 541e1051a39Sopenharmony_ci return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", 542e1051a39Sopenharmony_ci _asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour, 543e1051a39Sopenharmony_ci stm.tm_min, stm.tm_sec, stm.tm_year + 1900, 544e1051a39Sopenharmony_ci (gmt ? " GMT" : "")) > 0; 545e1051a39Sopenharmony_ci } 546e1051a39Sopenharmony_ci } 547e1051a39Sopenharmony_ci} 548e1051a39Sopenharmony_ci 549e1051a39Sopenharmony_ciint ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t) 550e1051a39Sopenharmony_ci{ 551e1051a39Sopenharmony_ci struct tm stm, ttm; 552e1051a39Sopenharmony_ci int day, sec; 553e1051a39Sopenharmony_ci 554e1051a39Sopenharmony_ci if (!ASN1_TIME_to_tm(s, &stm)) 555e1051a39Sopenharmony_ci return -2; 556e1051a39Sopenharmony_ci 557e1051a39Sopenharmony_ci if (!OPENSSL_gmtime(&t, &ttm)) 558e1051a39Sopenharmony_ci return -2; 559e1051a39Sopenharmony_ci 560e1051a39Sopenharmony_ci if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm)) 561e1051a39Sopenharmony_ci return -2; 562e1051a39Sopenharmony_ci 563e1051a39Sopenharmony_ci if (day > 0 || sec > 0) 564e1051a39Sopenharmony_ci return 1; 565e1051a39Sopenharmony_ci if (day < 0 || sec < 0) 566e1051a39Sopenharmony_ci return -1; 567e1051a39Sopenharmony_ci return 0; 568e1051a39Sopenharmony_ci} 569e1051a39Sopenharmony_ci 570e1051a39Sopenharmony_ciint ASN1_TIME_normalize(ASN1_TIME *t) 571e1051a39Sopenharmony_ci{ 572e1051a39Sopenharmony_ci struct tm tm; 573e1051a39Sopenharmony_ci 574e1051a39Sopenharmony_ci if (!ASN1_TIME_to_tm(t, &tm)) 575e1051a39Sopenharmony_ci return 0; 576e1051a39Sopenharmony_ci 577e1051a39Sopenharmony_ci return ossl_asn1_time_from_tm(t, &tm, V_ASN1_UNDEF) != NULL; 578e1051a39Sopenharmony_ci} 579e1051a39Sopenharmony_ci 580e1051a39Sopenharmony_ciint ASN1_TIME_compare(const ASN1_TIME *a, const ASN1_TIME *b) 581e1051a39Sopenharmony_ci{ 582e1051a39Sopenharmony_ci int day, sec; 583e1051a39Sopenharmony_ci 584e1051a39Sopenharmony_ci if (!ASN1_TIME_diff(&day, &sec, b, a)) 585e1051a39Sopenharmony_ci return -2; 586e1051a39Sopenharmony_ci if (day > 0 || sec > 0) 587e1051a39Sopenharmony_ci return 1; 588e1051a39Sopenharmony_ci if (day < 0 || sec < 0) 589e1051a39Sopenharmony_ci return -1; 590e1051a39Sopenharmony_ci return 0; 591e1051a39Sopenharmony_ci} 592