xref: /openbsd-src/regress/lib/libcrypto/asn1/rfc5280time.c (revision 72c7c57a68e32c57ac752161b5a93464ad11e7e1)
1*72c7c57aSbeck /* $OpenBSD: rfc5280time.c,v 1.8 2024/04/08 19:57:40 beck Exp $ */
22a6a270cSbeck /*
32a6a270cSbeck  * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
42a6a270cSbeck  * Copyright (c) 2015 Bob Beck <beck@opebsd.org>
52a6a270cSbeck  *
62a6a270cSbeck  * Permission to use, copy, modify, and distribute this software for any
72a6a270cSbeck  * purpose with or without fee is hereby granted, provided that the above
82a6a270cSbeck  * copyright notice and this permission notice appear in all copies.
92a6a270cSbeck  *
102a6a270cSbeck  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112a6a270cSbeck  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122a6a270cSbeck  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132a6a270cSbeck  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142a6a270cSbeck  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152a6a270cSbeck  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162a6a270cSbeck  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172a6a270cSbeck  */
182a6a270cSbeck 
192a6a270cSbeck #include <openssl/asn1.h>
202a6a270cSbeck #include <openssl/x509.h>
212a6a270cSbeck 
222a6a270cSbeck #include <err.h>
232a6a270cSbeck #include <stdio.h>
242a6a270cSbeck #include <string.h>
252a6a270cSbeck 
262a6a270cSbeck struct rfc5280_time_test {
272a6a270cSbeck 	const char *str;
282a6a270cSbeck 	const char *data;
292a6a270cSbeck 	time_t time;
302a6a270cSbeck };
312a6a270cSbeck 
322a6a270cSbeck struct rfc5280_time_test rfc5280_invtime_tests[] = {
332a6a270cSbeck 	{
342a6a270cSbeck 		.str = "",
352a6a270cSbeck 	},
362a6a270cSbeck 	{
372a6a270cSbeck 		.str = "2015",
382a6a270cSbeck 	},
392a6a270cSbeck 	{
402a6a270cSbeck 		.str = "201509",
412a6a270cSbeck 	},
422a6a270cSbeck 	{
432a6a270cSbeck 		.str = "20150923",
442a6a270cSbeck 	},
452a6a270cSbeck 	{
462a6a270cSbeck 		.str = "20150923032700",
472a6a270cSbeck 	},
482a6a270cSbeck 	{
492a6a270cSbeck 		/* UTC time must have seconds */
502a6a270cSbeck 		.str = "7001010000Z",
512a6a270cSbeck 	},
522a6a270cSbeck 	{
532a6a270cSbeck 		.str = "201509230327Z",
542a6a270cSbeck 	},
552a6a270cSbeck 	{
562a6a270cSbeck 		.str = "20150923032700.Z",
572a6a270cSbeck 	},
582a6a270cSbeck 	{
592a6a270cSbeck 		.str = "20150923032700.123",
602a6a270cSbeck 	},
612a6a270cSbeck 	{
622a6a270cSbeck 		.str = "20150923032700+1100Z",
632a6a270cSbeck 	},
642a6a270cSbeck 	{
652a6a270cSbeck 		.str = "20150923032700-11001",
662a6a270cSbeck 	},
672a6a270cSbeck 	{
682a6a270cSbeck 		/* UTC time cannot have fractional seconds. */
692a6a270cSbeck 		.str = "150923032700.123Z",
702a6a270cSbeck 	},
712a6a270cSbeck 	{
722a6a270cSbeck 		/* Gen time cannot have +- TZ. */
732a6a270cSbeck 		.str = "20150923032712+1115",
742a6a270cSbeck 	},
752a6a270cSbeck 	{
762a6a270cSbeck 		/* Gen time cannot have fractional seconds */
772a6a270cSbeck 		.str = "20150923032712.123Z",
782a6a270cSbeck 	},
792a6a270cSbeck 	{
802a6a270cSbeck 		.str = "aaaaaaaaaaaaaaZ",
812a6a270cSbeck 	},
822a6a270cSbeck 	{
837554eaecSbeck 		/* Must be a UTC time per RFC 5280 */
842a6a270cSbeck 		.str = "19700101000000Z",
852a6a270cSbeck 		.data = "19700101000000Z",
862a6a270cSbeck 		.time = 0,
872a6a270cSbeck 	},
882a6a270cSbeck 	{
897554eaecSbeck 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
902a6a270cSbeck 		.str = "20150923032700Z",
912a6a270cSbeck 		.data = "20150923032700Z",
922a6a270cSbeck 		.time = 1442978820,
932a6a270cSbeck 	},
942a6a270cSbeck 	{
957554eaecSbeck 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
967554eaecSbeck 		.str = "00000101000000Z",
977554eaecSbeck 		.data = "00000101000000Z",
983221a44fSmiod 		.time = -62167219200LL,
992a6a270cSbeck 	},
1002a6a270cSbeck 	{
1017554eaecSbeck 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
1027554eaecSbeck 		.str = "20491231235959Z",
1037554eaecSbeck 		.data = "20491231235959Z",
1043221a44fSmiod 		.time = 2524607999LL,
1052a6a270cSbeck 	},
1062a6a270cSbeck 	{
1077554eaecSbeck 		/* (times before 2050 must be UTCTIME) Per RFC 5280 4.1.2.5 */
1087554eaecSbeck 		.str = "19500101000000Z",
1097554eaecSbeck 		.data = "19500101000000Z",
1103221a44fSmiod 		.time = -631152000LL,
1112a6a270cSbeck 	},
1127554eaecSbeck };
1137554eaecSbeck 
1147554eaecSbeck struct rfc5280_time_test rfc5280_gentime_tests[] = {
1152a6a270cSbeck 	{
1162a6a270cSbeck 		/* Biggest RFC 5280 time */
1172a6a270cSbeck 		.str = "99991231235959Z",
1182a6a270cSbeck 		.data = "99991231235959Z",
1193221a44fSmiod 		.time = 253402300799LL,
1202a6a270cSbeck 	},
1212a6a270cSbeck 	{
1227554eaecSbeck 		.str = "21600218104000Z",
1237554eaecSbeck 		.data = "21600218104000Z",
1243221a44fSmiod 		.time = 6000000000LL,
1257554eaecSbeck 	},
1267554eaecSbeck 	{
1277554eaecSbeck 		/* Smallest RFC 5280 gen time */
1287554eaecSbeck 		.str = "20500101000000Z",
1297554eaecSbeck 		.data = "20500101000000Z",
1303221a44fSmiod 		.time =  2524608000LL,
1312a6a270cSbeck 	},
1322a6a270cSbeck };
1332a6a270cSbeck struct rfc5280_time_test rfc5280_utctime_tests[] = {
1342a6a270cSbeck 	{
1357554eaecSbeck 		.str = "500101000000Z",
1367554eaecSbeck 		.data = "500101000000Z",
1377554eaecSbeck 		.time = -631152000,
1387554eaecSbeck 	},
1397554eaecSbeck 	{
1407554eaecSbeck 		.str = "540226230640Z",
1417554eaecSbeck 		.data = "540226230640Z",
1427554eaecSbeck 		.time = -500000000,
1437554eaecSbeck 	},
1447554eaecSbeck 	{
1457554eaecSbeck 		.str = "491231235959Z",
1467554eaecSbeck 		.data = "491231235959Z",
1473221a44fSmiod 		.time = 2524607999LL,
1487554eaecSbeck 	},
1497554eaecSbeck 	{
1502a6a270cSbeck 		.str = "700101000000Z",
1512a6a270cSbeck 		.data = "700101000000Z",
1522a6a270cSbeck 		.time = 0,
1532a6a270cSbeck 	},
1542a6a270cSbeck 	{
1552a6a270cSbeck 		.str = "150923032700Z",
1562a6a270cSbeck 		.data = "150923032700Z",
1572a6a270cSbeck 		.time = 1442978820,
1582a6a270cSbeck 	},
1592a6a270cSbeck 	{
1602a6a270cSbeck 		.str = "150923102700Z",
1612a6a270cSbeck 		.data = "150923102700Z",
1622a6a270cSbeck 		.time = 1443004020,
1632a6a270cSbeck 	},
1642a6a270cSbeck 	{
1652a6a270cSbeck 		.str = "150922162712Z",
1662a6a270cSbeck 		.data = "150922162712Z",
1672a6a270cSbeck 		.time = 1442939232,
1682a6a270cSbeck 	},
1692a6a270cSbeck 	{
1702a6a270cSbeck 		.str = "140524144512Z",
1712a6a270cSbeck 		.data = "140524144512Z",
1722a6a270cSbeck 		.time = 1400942712,
1732a6a270cSbeck 	},
1742a6a270cSbeck 	{
1752a6a270cSbeck 		.str = "240401144512Z",
1762a6a270cSbeck 		.data = "240401144512Z",
1772a6a270cSbeck 		.time = 1711982712,
1782a6a270cSbeck 	},
1792a6a270cSbeck };
1802a6a270cSbeck 
1812a6a270cSbeck #define N_INVTIME_TESTS \
1822a6a270cSbeck     (sizeof(rfc5280_invtime_tests) / sizeof(*rfc5280_invtime_tests))
1832a6a270cSbeck #define N_GENTIME_TESTS \
1842a6a270cSbeck     (sizeof(rfc5280_gentime_tests) / sizeof(*rfc5280_gentime_tests))
1852a6a270cSbeck #define N_UTCTIME_TESTS \
1862a6a270cSbeck     (sizeof(rfc5280_utctime_tests) / sizeof(*rfc5280_utctime_tests))
1872a6a270cSbeck 
1882a6a270cSbeck static int
asn1_compare_str(int test_no,struct asn1_string_st * asn1str,const char * str)1892a6a270cSbeck asn1_compare_str(int test_no, struct asn1_string_st *asn1str, const char *str)
1902a6a270cSbeck {
1912a6a270cSbeck 	int length = strlen(str);
1922a6a270cSbeck 
1932a6a270cSbeck 	if (asn1str->length != length) {
1947bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - string lengths differ "
1957bb1a6cfStb 		    "(%d != %d)\n", test_no, asn1str->length, length);
1962a6a270cSbeck 		return (1);
1972a6a270cSbeck 	}
1982a6a270cSbeck 	if (strncmp(asn1str->data, str, length) != 0) {
1997bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - strings differ "
2002a6a270cSbeck 		    "('%s' != '%s')\n", test_no, asn1str->data, str);
2012a6a270cSbeck 		return (1);
2022a6a270cSbeck 	}
2032a6a270cSbeck 
2042a6a270cSbeck 	return (0);
2052a6a270cSbeck }
2062a6a270cSbeck 
2072a6a270cSbeck static int
rfc5280_invtime_test(int test_no,struct rfc5280_time_test * att)2082a6a270cSbeck rfc5280_invtime_test(int test_no, struct rfc5280_time_test *att)
2092a6a270cSbeck {
2102a6a270cSbeck 	ASN1_GENERALIZEDTIME *gt = NULL;
2112a6a270cSbeck 	ASN1_UTCTIME *ut = NULL;
2122a6a270cSbeck 	ASN1_TIME *t = NULL;
2132a6a270cSbeck 	int failure = 1;
2142a6a270cSbeck 	time_t now = time(NULL);
2152a6a270cSbeck 
2162a6a270cSbeck 	if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
2172a6a270cSbeck 		goto done;
2182a6a270cSbeck 	if ((ut = ASN1_UTCTIME_new()) == NULL)
2192a6a270cSbeck 		goto done;
2202a6a270cSbeck 	if ((t = ASN1_TIME_new()) == NULL)
2212a6a270cSbeck 		goto done;
2222a6a270cSbeck 
2232a6a270cSbeck 	if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 0) {
2242a6a270cSbeck 		if (X509_cmp_time(gt, &now) != 0) {
2257bb1a6cfStb 			fprintf(stderr, "FAIL: test %d - successfully parsed as GENTIME "
2262a6a270cSbeck 			    "string '%s'\n", test_no, att->str);
2272a6a270cSbeck 			goto done;
2282a6a270cSbeck 		}
2292a6a270cSbeck 	}
2302a6a270cSbeck 	if (ASN1_UTCTIME_set_string(ut, att->str) != 0) {
2312a6a270cSbeck 		if (X509_cmp_time(ut, &now) != 0) {
2327bb1a6cfStb 			fprintf(stderr, "FAIL: test %d - successfully parsed as UTCTIME "
2332a6a270cSbeck 			    "string '%s'\n", test_no, att->str);
2342a6a270cSbeck 			goto done;
2352a6a270cSbeck 		}
2362a6a270cSbeck 	}
2372a6a270cSbeck 
2382a6a270cSbeck 	failure = 0;
2392a6a270cSbeck 
2402a6a270cSbeck  done:
2412a6a270cSbeck 	ASN1_GENERALIZEDTIME_free(gt);
2422a6a270cSbeck 	ASN1_UTCTIME_free(ut);
2432a6a270cSbeck 	ASN1_TIME_free(t);
2442a6a270cSbeck 
2452a6a270cSbeck 	return (failure);
2462a6a270cSbeck }
2472a6a270cSbeck 
2482a6a270cSbeck static int
rfc5280_gentime_test(int test_no,struct rfc5280_time_test * att)2492a6a270cSbeck rfc5280_gentime_test(int test_no, struct rfc5280_time_test *att)
2502a6a270cSbeck {
2512a6a270cSbeck 	unsigned char *p = NULL;
2522a6a270cSbeck 	ASN1_GENERALIZEDTIME *gt;
2532a6a270cSbeck 	int failure = 1;
2542a6a270cSbeck 	int i;
2552a6a270cSbeck 
2562a6a270cSbeck 	if ((gt = ASN1_GENERALIZEDTIME_new()) == NULL)
2572a6a270cSbeck 		goto done;
2582a6a270cSbeck 
2592a6a270cSbeck 	if (ASN1_GENERALIZEDTIME_set_string(gt, att->str) != 1) {
2607bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n",
2612a6a270cSbeck 		    test_no, att->str);
2622a6a270cSbeck 		goto done;
2632a6a270cSbeck 	}
2642a6a270cSbeck 	if (asn1_compare_str(test_no, gt, att->str) != 0)
2652a6a270cSbeck 		goto done;
2662a6a270cSbeck 
2677554eaecSbeck 	if ((i = X509_cmp_time(gt, &att->time)) != -1) {
2687bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
2694a262ce0Stb 		    test_no, i, (long long)att->time);
2702a6a270cSbeck 		goto done;
2712a6a270cSbeck 	}
2722a6a270cSbeck 
2732a6a270cSbeck 	att->time--;
2747554eaecSbeck 	if ((i = X509_cmp_time(gt, &att->time)) != 1) {
2757bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
2764a262ce0Stb 		    test_no, i, (long long)att->time);
2772a6a270cSbeck 		goto done;
2782a6a270cSbeck 	}
2792a6a270cSbeck 	att->time++;
2802a6a270cSbeck 
2812a6a270cSbeck 	ASN1_GENERALIZEDTIME_free(gt);
2822a6a270cSbeck 
2832a6a270cSbeck 	if ((gt = ASN1_GENERALIZEDTIME_set(NULL, att->time)) == NULL) {
2847bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - failed to set time %lld\n",
2852a6a270cSbeck 		    test_no, (long long)att->time);
2862a6a270cSbeck 		goto done;
2872a6a270cSbeck 	}
2882a6a270cSbeck 	if (asn1_compare_str(test_no, gt, att->data) != 0)
2892a6a270cSbeck 		goto done;
2902a6a270cSbeck 
2912a6a270cSbeck 	failure = 0;
2922a6a270cSbeck 
2932a6a270cSbeck  done:
2942a6a270cSbeck 	ASN1_GENERALIZEDTIME_free(gt);
2952a6a270cSbeck 	free(p);
2962a6a270cSbeck 
2972a6a270cSbeck 	return (failure);
2982a6a270cSbeck }
2992a6a270cSbeck 
3002a6a270cSbeck static int
rfc5280_utctime_test(int test_no,struct rfc5280_time_test * att)3012a6a270cSbeck rfc5280_utctime_test(int test_no, struct rfc5280_time_test *att)
3022a6a270cSbeck {
3032a6a270cSbeck 	unsigned char *p = NULL;
3042a6a270cSbeck 	ASN1_UTCTIME *ut;
3052a6a270cSbeck 	int failure = 1;
3062a6a270cSbeck 	int i;
3072a6a270cSbeck 
3082a6a270cSbeck 	if ((ut = ASN1_UTCTIME_new()) == NULL)
3092a6a270cSbeck 		goto done;
3102a6a270cSbeck 
3112a6a270cSbeck 	if (ASN1_UTCTIME_set_string(ut, att->str) != 1) {
3127bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - failed to set string '%s'\n",
3132a6a270cSbeck 		    test_no, att->str);
3142a6a270cSbeck 		goto done;
3152a6a270cSbeck 	}
3162a6a270cSbeck 	if (asn1_compare_str(test_no, ut, att->str) != 0)
3172a6a270cSbeck 		goto done;
3182a6a270cSbeck 
3197554eaecSbeck 	if ((i = X509_cmp_time(ut, &att->time)) != -1) {
3207bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
321898fc41dStb 		    test_no, i, (long long)att->time);
3222a6a270cSbeck 		goto done;
3232a6a270cSbeck 	}
3242a6a270cSbeck 
3252a6a270cSbeck 	att->time--;
3267554eaecSbeck 	if ((i = X509_cmp_time(ut, &att->time)) != 1) {
3277bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - X509_cmp_time failed - returned %d compared to %lld\n",
328898fc41dStb 		    test_no, i, (long long)att->time);
3292a6a270cSbeck 		goto done;
3302a6a270cSbeck 	}
3312a6a270cSbeck 	att->time++;
3322a6a270cSbeck 
3332a6a270cSbeck 	ASN1_UTCTIME_free(ut);
3342a6a270cSbeck 
3352a6a270cSbeck 	if ((ut = ASN1_UTCTIME_set(NULL, att->time)) == NULL) {
3367bb1a6cfStb 		fprintf(stderr, "FAIL: test %d - failed to set time %lld\n",
3372a6a270cSbeck 		    test_no, (long long)att->time);
3382a6a270cSbeck 		goto done;
3392a6a270cSbeck 	}
3402a6a270cSbeck 	if (asn1_compare_str(test_no, ut, att->data) != 0)
3412a6a270cSbeck 		goto done;
3422a6a270cSbeck 
3432a6a270cSbeck 	failure = 0;
3442a6a270cSbeck 
3452a6a270cSbeck  done:
3462a6a270cSbeck 	ASN1_UTCTIME_free(ut);
3472a6a270cSbeck 	free(p);
3482a6a270cSbeck 
3492a6a270cSbeck 	return (failure);
3502a6a270cSbeck }
3512a6a270cSbeck 
3522a6a270cSbeck int
main(int argc,char ** argv)3532a6a270cSbeck main(int argc, char **argv)
3542a6a270cSbeck {
3552a6a270cSbeck 	struct rfc5280_time_test *att;
3562a6a270cSbeck 	int failed = 0;
3572a6a270cSbeck 	size_t i;
3582a6a270cSbeck 
3592a6a270cSbeck 	fprintf(stderr, "RFC5280 Invalid time tests...\n");
3602a6a270cSbeck 	for (i = 0; i < N_INVTIME_TESTS; i++) {
3612a6a270cSbeck 		att = &rfc5280_invtime_tests[i];
3622a6a270cSbeck 		failed |= rfc5280_invtime_test(i, att);
3632a6a270cSbeck 	}
3642a6a270cSbeck 
3652a6a270cSbeck 	fprintf(stderr, "RFC5280 GENERALIZEDTIME tests...\n");
3662a6a270cSbeck 	for (i = 0; i < N_GENTIME_TESTS; i++) {
3672a6a270cSbeck 		att = &rfc5280_gentime_tests[i];
3682a6a270cSbeck 		failed |= rfc5280_gentime_test(i, att);
3692a6a270cSbeck 	}
3702a6a270cSbeck 
3712a6a270cSbeck 	fprintf(stderr, "RFC5280 UTCTIME tests...\n");
3722a6a270cSbeck 	for (i = 0; i < N_UTCTIME_TESTS; i++) {
3732a6a270cSbeck 		att = &rfc5280_utctime_tests[i];
3742a6a270cSbeck 		failed |= rfc5280_utctime_test(i, att);
3752a6a270cSbeck 	}
3762a6a270cSbeck 	return (failed);
3772a6a270cSbeck }
378