1 /* $OpenBSD: rfc5280time.c,v 1.4 2015/10/30 15:52:55 miod 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 26 struct rfc5280_time_test { 27 const char *str; 28 const char *data; 29 time_t time; 30 }; 31 32 struct 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 114 struct 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 }; 133 struct 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 188 static int 189 asn1_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 %i - string lengths differ " 195 "(%i != %i)\n", test_no, asn1str->length, length); 196 return (1); 197 } 198 if (strncmp(asn1str->data, str, length) != 0) { 199 fprintf(stderr, "FAIL: test %i - strings differ " 200 "('%s' != '%s')\n", test_no, asn1str->data, str); 201 return (1); 202 } 203 204 return (0); 205 } 206 207 static int 208 rfc5280_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 %i - 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 %i - successfully parsed as UTCTIME " 233 "string '%s'\n", test_no, att->str); 234 goto done; 235 } 236 } 237 if (ASN1_TIME_set_string(t, att->str) != 0) { 238 if (X509_cmp_time(t, &now) != 0) { 239 fprintf(stderr, "FAIL: test %i - successfully parsed as UTCTIME " 240 "string '%s'\n", test_no, att->str); 241 goto done; 242 } 243 } 244 245 failure = 0; 246 247 done: 248 ASN1_GENERALIZEDTIME_free(gt); 249 ASN1_UTCTIME_free(ut); 250 ASN1_TIME_free(t); 251 252 return (failure); 253 } 254 255 static int 256 rfc5280_gentime_test(int test_no, struct rfc5280_time_test *att) 257 { 258 unsigned char *p = NULL; 259 ASN1_GENERALIZEDTIME *gt; 260 int failure = 1; 261 int i; 262 263 if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL) 264 goto done; 265 266 if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) { 267 fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n", 268 test_no, att->str); 269 goto done; 270 } 271 if (asn1_compare_str(test_no, gt, att->str) != 0) 272 goto done; 273 274 if ((i = X509_cmp_time(gt, &att->time)) != -1) { 275 fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n", 276 test_no, i, att->time); 277 goto done; 278 } 279 280 att->time--; 281 if ((i = X509_cmp_time(gt, &att->time)) != 1) { 282 fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n", 283 test_no, i, att->time); 284 goto done; 285 } 286 att->time++; 287 288 ASN1_GENERALIZEDTIME_free(gt); 289 290 if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) { 291 fprintf(stderr, "FAIL: test %i - failed to set time %lli\n", 292 test_no, (long long)att->time); 293 goto done; 294 } 295 if (asn1_compare_str(test_no, gt, att->data) != 0) 296 goto done; 297 298 failure = 0; 299 300 done: 301 ASN1_GENERALIZEDTIME_free(gt); 302 free(p); 303 304 return (failure); 305 } 306 307 static int 308 rfc5280_utctime_test(int test_no, struct rfc5280_time_test *att) 309 { 310 unsigned char *p = NULL; 311 ASN1_UTCTIME *ut; 312 int failure = 1; 313 int i; 314 315 if ((ut = ASN1_UTCTIME_new()) == NULL) 316 goto done; 317 318 if (ASN1_UTCTIME_set_string(ut, att->str) != 1) { 319 fprintf(stderr, "FAIL: test %i - failed to set string '%s'\n", 320 test_no, att->str); 321 goto done; 322 } 323 if (asn1_compare_str(test_no, ut, att->str) != 0) 324 goto done; 325 326 if ((i = X509_cmp_time(ut, &att->time)) != -1) { 327 fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n", 328 test_no, i, att->time); 329 goto done; 330 } 331 332 att->time--; 333 if ((i = X509_cmp_time(ut, &att->time)) != 1) { 334 fprintf(stderr, "FAIL: test %i - X509_cmp_time failed - returned %d compared to %lld\n", 335 test_no, i, att->time); 336 goto done; 337 } 338 att->time++; 339 340 ASN1_UTCTIME_free(ut); 341 342 if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) { 343 fprintf(stderr, "FAIL: test %i - failed to set time %lli\n", 344 test_no, (long long)att->time); 345 goto done; 346 } 347 if (asn1_compare_str(test_no, ut, att->data) != 0) 348 goto done; 349 350 failure = 0; 351 352 done: 353 ASN1_UTCTIME_free(ut); 354 free(p); 355 356 return (failure); 357 } 358 359 int 360 main(int argc, char **argv) 361 { 362 struct rfc5280_time_test *att; 363 int failed = 0; 364 size_t i; 365 366 fprintf(stderr, "RFC5280 Invalid time tests...\n"); 367 for (i = 0; i < N_INVTIME_TESTS; i++) { 368 att = &rfc5280_invtime_tests[i]; 369 failed |= rfc5280_invtime_test(i, att); 370 } 371 372 fprintf(stderr, "RFC5280 GENERALIZEDTIME tests...\n"); 373 for (i = 0; i < N_GENTIME_TESTS; i++) { 374 att = &rfc5280_gentime_tests[i]; 375 failed |= rfc5280_gentime_test(i, att); 376 } 377 378 fprintf(stderr, "RFC5280 UTCTIME tests...\n"); 379 for (i = 0; i < N_UTCTIME_TESTS; i++) { 380 att = &rfc5280_utctime_tests[i]; 381 failed |= rfc5280_utctime_test(i, att); 382 } 383 return (failed); 384 } 385