1/* $OpenBSD: rfc5280time.c,v 1.8 2024/04/08 19:57:40 beck Exp $ */ 2/* 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 4 * Copyright (c) 2015 Bob Beck <beck@opebsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <openssl/asn1.h> 20#include <openssl/x509.h> 21 22#include <err.h> 23#include <stdio.h> 24#include <string.h> 25 26struct rfc5280_time_test { 27 const char *str; 28 const char *data; 29 time_t time; 30}; 31 32struct rfc5280_time_test rfc5280_invtime_tests[] = { 33 { 34 .str = "", 35 }, 36 { 37 .str = "2015", 38 }, 39 { 40 .str = "201509", 41 }, 42 { 43 .str = "20150923", 44 }, 45 { 46 .str = "20150923032700", 47 }, 48 { 49 /* UTC time must have seconds */ 50 .str = "7001010000Z", 51 }, 52 { 53 .str = "201509230327Z", 54 }, 55 { 56 .str = "20150923032700.Z", 57 }, 58 { 59 .str = "20150923032700.123", 60 }, 61 { 62 .str = "20150923032700+1100Z", 63 }, 64 { 65 .str = "20150923032700-11001", 66 }, 67 { 68 /* UTC time cannot have fractional seconds. */ 69 .str = "150923032700.123Z", 70 }, 71 { 72 /* Gen time cannot have +- TZ. */ 73 .str = "20150923032712+1115", 74 }, 75 { 76 /* Gen time cannot have fractional seconds */ 77 .str = "20150923032712.123Z", 78 }, 79 { 80 .str = "aaaaaaaaaaaaaaZ", 81 }, 82 { 83 /* Must be a UTC time per RFC 5280 */ 84 .str = "19700101000000Z", 85 .data = "19700101000000Z", 86 .time = 0, 87 }, 88 { 89 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */ 90 .str = "20150923032700Z", 91 .data = "20150923032700Z", 92 .time = 1442978820, 93 }, 94 { 95 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */ 96 .str = "00000101000000Z", 97 .data = "00000101000000Z", 98 .time = -62167219200LL, 99 }, 100 { 101 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */ 102 .str = "20491231235959Z", 103 .data = "20491231235959Z", 104 .time = 2524607999LL, 105 }, 106 { 107 /* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */ 108 .str = "19500101000000Z", 109 .data = "19500101000000Z", 110 .time = -631152000LL, 111 }, 112}; 113 114struct rfc5280_time_test rfc5280_gentime_tests[] = { 115 { 116 /* Biggest RFC 5280 time */ 117 .str = "99991231235959Z", 118 .data = "99991231235959Z", 119 .time = 253402300799LL, 120 }, 121 { 122 .str = "21600218104000Z", 123 .data = "21600218104000Z", 124 .time = 6000000000LL, 125 }, 126 { 127 /* Smallest RFC 5280 gen time */ 128 .str = "20500101000000Z", 129 .data = "20500101000000Z", 130 .time = 2524608000LL, 131 }, 132}; 133struct rfc5280_time_test rfc5280_utctime_tests[] = { 134 { 135 .str = "500101000000Z", 136 .data = "500101000000Z", 137 .time = -631152000, 138 }, 139 { 140 .str = "540226230640Z", 141 .data = "540226230640Z", 142 .time = -500000000, 143 }, 144 { 145 .str = "491231235959Z", 146 .data = "491231235959Z", 147 .time = 2524607999LL, 148 }, 149 { 150 .str = "700101000000Z", 151 .data = "700101000000Z", 152 .time = 0, 153 }, 154 { 155 .str = "150923032700Z", 156 .data = "150923032700Z", 157 .time = 1442978820, 158 }, 159 { 160 .str = "150923102700Z", 161 .data = "150923102700Z", 162 .time = 1443004020, 163 }, 164 { 165 .str = "150922162712Z", 166 .data = "150922162712Z", 167 .time = 1442939232, 168 }, 169 { 170 .str = "140524144512Z", 171 .data = "140524144512Z", 172 .time = 1400942712, 173 }, 174 { 175 .str = "240401144512Z", 176 .data = "240401144512Z", 177 .time = 1711982712, 178 }, 179}; 180 181#define N_INVTIME_TESTS \ 182 (sizeof(rfc5280_invtime_tests) / sizeof(*rfc5280_invtime_tests)) 183#define N_GENTIME_TESTS \ 184 (sizeof(rfc5280_gentime_tests) / sizeof(*rfc5280_gentime_tests)) 185#define N_UTCTIME_TESTS \ 186 (sizeof(rfc5280_utctime_tests) / sizeof(*rfc5280_utctime_tests)) 187 188static int 189asn1_compare_str(int test_no, struct asn1_string_st *asn1str, const char *str) 190{ 191 int length = strlen(str); 192 193 if (asn1str->length != length) { 194 fprintf(stderr, "FAIL: test %d - string lengths differ " 195 "(%d != %d)\n", test_no, asn1str->length, length); 196 return (1); 197 } 198 if (strncmp(asn1str->data, str, length) != 0) { 199 fprintf(stderr, "FAIL: test %d - strings differ " 200 "('%s' != '%s')\n", test_no, asn1str->data, str); 201 return (1); 202 } 203 204 return (0); 205} 206 207static int 208rfc5280_invtime_test(int test_no, struct rfc5280_time_test *att) 209{ 210 ASN1_GENERALIZEDTIME *gt = NULL; 211 ASN1_UTCTIME *ut = NULL; 212 ASN1_TIME *t = NULL; 213 int failure = 1; 214 time_t now = time(NULL); 215 216 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL) 217 goto done; 218 if ((ut = ASN1_UTCTIME_new()) == NULL) 219 goto done; 220 if ((t = ASN1_TIME_new()) == NULL) 221 goto done; 222 223 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 0) { 224 if (X509_cmp_time(gt, &now) != 0) { 225 fprintf(stderr, "FAIL: test %d - successfully parsed as GENTIME " 226 "string '%s'\n", test_no, att->str); 227 goto done; 228 } 229 } 230 if (ASN1_UTCTIME_set_string(ut, att->str) != 0) { 231 if (X509_cmp_time(ut, &now) != 0) { 232 fprintf(stderr, "FAIL: test %d - successfully parsed as UTCTIME " 233 "string '%s'\n", test_no, att->str); 234 goto done; 235 } 236 } 237 238 failure = 0; 239 240 done: 241 ASN1_GENERALIZEDTIME_free(gt); 242 ASN1_UTCTIME_free(ut); 243 ASN1_TIME_free(t); 244 245 return (failure); 246} 247 248static int 249rfc5280_gentime_test(int test_no, struct rfc5280_time_test *att) 250{ 251 unsigned char *p = NULL; 252 ASN1_GENERALIZEDTIME *gt; 253 int failure = 1; 254 int i; 255 256 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL) 257 goto done; 258 259 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) { 260 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 261 test_no, att->str); 262 goto done; 263 } 264 if (asn1_compare_str(test_no, gt, att->str) != 0) 265 goto done; 266 267 if ((i = X509_cmp_time(gt, &att->time)) != -1) { 268 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n", 269 test_no, i, (long long)att->time); 270 goto done; 271 } 272 273 att->time--; 274 if ((i = X509_cmp_time(gt, &att->time)) != 1) { 275 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n", 276 test_no, i, (long long)att->time); 277 goto done; 278 } 279 att->time++; 280 281 ASN1_GENERALIZEDTIME_free(gt); 282 283 if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) { 284 fprintf(stderr, "FAIL: test %d - failed to set time %lld\n", 285 test_no, (long long)att->time); 286 goto done; 287 } 288 if (asn1_compare_str(test_no, gt, att->data) != 0) 289 goto done; 290 291 failure = 0; 292 293 done: 294 ASN1_GENERALIZEDTIME_free(gt); 295 free(p); 296 297 return (failure); 298} 299 300static int 301rfc5280_utctime_test(int test_no, struct rfc5280_time_test *att) 302{ 303 unsigned char *p = NULL; 304 ASN1_UTCTIME *ut; 305 int failure = 1; 306 int i; 307 308 if ((ut = ASN1_UTCTIME_new()) == NULL) 309 goto done; 310 311 if (ASN1_UTCTIME_set_string(ut, att->str) != 1) { 312 fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n", 313 test_no, att->str); 314 goto done; 315 } 316 if (asn1_compare_str(test_no, ut, att->str) != 0) 317 goto done; 318 319 if ((i = X509_cmp_time(ut, &att->time)) != -1) { 320 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n", 321 test_no, i, (long long)att->time); 322 goto done; 323 } 324 325 att->time--; 326 if ((i = X509_cmp_time(ut, &att->time)) != 1) { 327 fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n", 328 test_no, i, (long long)att->time); 329 goto done; 330 } 331 att->time++; 332 333 ASN1_UTCTIME_free(ut); 334 335 if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) { 336 fprintf(stderr, "FAIL: test %d - failed to set time %lld\n", 337 test_no, (long long)att->time); 338 goto done; 339 } 340 if (asn1_compare_str(test_no, ut, att->data) != 0) 341 goto done; 342 343 failure = 0; 344 345 done: 346 ASN1_UTCTIME_free(ut); 347 free(p); 348 349 return (failure); 350} 351 352int 353main(int argc, char **argv) 354{ 355 struct rfc5280_time_test *att; 356 int failed = 0; 357 size_t i; 358 359 fprintf(stderr, "RFC5280 Invalid time tests...\n"); 360 for (i = 0; i < N_INVTIME_TESTS; i++) { 361 att = &rfc5280_invtime_tests[i]; 362 failed |= rfc5280_invtime_test(i, att); 363 } 364 365 fprintf(stderr, "RFC5280 GENERALIZEDTIME tests...\n"); 366 for (i = 0; i < N_GENTIME_TESTS; i++) { 367 att = &rfc5280_gentime_tests[i]; 368 failed |= rfc5280_gentime_test(i, att); 369 } 370 371 fprintf(stderr, "RFC5280 UTCTIME tests...\n"); 372 for (i = 0; i < N_UTCTIME_TESTS; i++) { 373 att = &rfc5280_utctime_tests[i]; 374 failed |= rfc5280_utctime_test(i, att); 375 } 376 return (failed); 377} 378