mirror of https://github.com/openssl/openssl.git
Add unit test for X509 temporal validity functions.
This commit is contained in:
parent
06ed41a5c8
commit
cc0577a803
|
|
@ -401,5 +401,7 @@ int ossl_x509_compare_asn1_time(const X509_VERIFY_PARAM *vpm,
|
|||
const ASN1_TIME *time, int *comparison);
|
||||
int ossl_x509_check_certificate_times(const X509_VERIFY_PARAM *vpm, X509 *x,
|
||||
int *error);
|
||||
/* No error callback if depth < 0 */
|
||||
int ossl_x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int depth);
|
||||
|
||||
#endif /* OSSL_CRYPTO_X509_H */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/*
|
||||
* Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
/* Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
|
|
@ -14,8 +13,10 @@
|
|||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
#include "testutil.h"
|
||||
#include "internal/nelem.h"
|
||||
#include "crypto/x509.h"
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
|
|
@ -221,10 +222,300 @@ static int tests_X509_PURPOSE(void)
|
|||
&& TEST_int_eq(X509_PURPOSE_get_id(xp), X509_PURPOSE_DEFAULT_ANY);
|
||||
}
|
||||
|
||||
/* 0000-01-01 00:00:00 UTC */
|
||||
#define MIN_CERT_TIME INT64_C(-62167219200)
|
||||
/* 9999-12-31 23:59:59 UTC */
|
||||
#define MAX_CERT_TIME INT64_C(253402300799)
|
||||
/* 1950-01-01 00:00:00 UTC */
|
||||
#define MIN_UTC_TIME INT64_C(-631152000)
|
||||
/* 2049-12-31 23:59:59 UTC */
|
||||
#define MAX_UTC_TIME INT64_C(2524607999)
|
||||
|
||||
typedef struct {
|
||||
int64_t NotBefore;
|
||||
int64_t NotAfter;
|
||||
} CERT_TEST_DATA;
|
||||
|
||||
/* clang-format off */
|
||||
static CERT_TEST_DATA cert_test_data[] = {
|
||||
{ 0, 0 },
|
||||
{ 0, 1 },
|
||||
{ 1, 1 },
|
||||
{ -1, 0 },
|
||||
{ -1, 1 },
|
||||
{ 1442939232, 1443004020 },
|
||||
{ 0, INT32_MAX },
|
||||
{ INT32_MIN, 0 },
|
||||
{ INT32_MIN, INT32_MAX },
|
||||
{ 0, UINT32_MAX },
|
||||
{ MIN_UTC_TIME, 0 },
|
||||
{ MIN_UTC_TIME - 1, 0 },
|
||||
{ 0, MAX_UTC_TIME },
|
||||
{ 0, MAX_UTC_TIME + 1 },
|
||||
{ MIN_UTC_TIME, MAX_UTC_TIME},
|
||||
{ MIN_UTC_TIME - 1, MAX_UTC_TIME + 1 },
|
||||
{ MIN_CERT_TIME, MAX_CERT_TIME },
|
||||
{ MIN_CERT_TIME, MAX_CERT_TIME - 1 },
|
||||
{ MIN_CERT_TIME + 1, MAX_CERT_TIME },
|
||||
{ MIN_CERT_TIME + 1, MAX_CERT_TIME - 1 },
|
||||
{ 0, MAX_CERT_TIME },
|
||||
{ 0, MAX_CERT_TIME - 1 }
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
/* Returns 0 for success, 1 if failed */
|
||||
static int test_a_time(X509_STORE_CTX *ctx, X509 *x509,
|
||||
const int64_t test_time,
|
||||
int64_t notBefore, int64_t notAfter,
|
||||
int64_t lower_limit, int64_t upper_limit) {
|
||||
int expected_value, error, expected_error;;
|
||||
X509_VERIFY_PARAM *vpm;
|
||||
|
||||
/* Skip tests out of time_t range */
|
||||
if (test_time < lower_limit || test_time > upper_limit)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* XXX beck This block below is a hack. The current comparison
|
||||
* routines needlessly convert the time_t value to a struct
|
||||
* tm to compare it to the asn1_string converted to a struct tm.
|
||||
* OPENSSL_gmtime() does this, but fails on large time_t values.
|
||||
* Once we remove this conversion we should be able to compare
|
||||
* against the full range of time_t. but for the moment we need
|
||||
* to skip this test if OPENSSL_gmtime() fails.
|
||||
*/
|
||||
{
|
||||
const time_t t = (const time_t) test_time;
|
||||
struct tm tm;
|
||||
|
||||
if (OPENSSL_gmtime(&t, &tm) == NULL) {
|
||||
TEST_info("OPENSSL_gmtime can't handle time of %lld, skipping test",
|
||||
(long long) test_time);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
expected_value = notBefore <= test_time;
|
||||
if (expected_value) {
|
||||
expected_value = notAfter == MAX_CERT_TIME || notAfter >= test_time;
|
||||
}
|
||||
|
||||
if (notBefore > test_time)
|
||||
expected_error = X509_V_ERR_CERT_NOT_YET_VALID;
|
||||
else if (notAfter < test_time && notAfter != MAX_CERT_TIME)
|
||||
expected_error = X509_V_ERR_CERT_HAS_EXPIRED;
|
||||
else
|
||||
expected_error = 0;
|
||||
|
||||
vpm = X509_STORE_CTX_get0_param(ctx);
|
||||
X509_VERIFY_PARAM_set_time(vpm, test_time);
|
||||
if (ossl_x509_check_cert_time(ctx, x509, 0) != expected_value) {
|
||||
TEST_info("ossl_X509_check_cert_time %s unexpectedly when verifying "
|
||||
"notBefore %lld, notAfter %lld at time %lld\n",
|
||||
expected_value ? "failed" : "succeeded",
|
||||
(long long)notBefore, (long long)notAfter,
|
||||
(long long)test_time);
|
||||
return 1;
|
||||
}
|
||||
error = 0;
|
||||
if (ossl_x509_check_certificate_times(vpm, x509, &error) != expected_value) {
|
||||
TEST_info("ossl_X509_check_certificate_times %s unexpectedly when "
|
||||
"verifying notBefore %lld, notAfter %lld at time %lld\n",
|
||||
expected_value ? "failed" : "succeeded",
|
||||
(long long)notBefore, (long long)notAfter,
|
||||
(long long)test_time);
|
||||
return 1;
|
||||
}
|
||||
if (error != expected_error) {
|
||||
TEST_info("ossl_X509_check_certificate_times error return was %d, "
|
||||
"expected %d when verifying notBefore %lld, notAfter %lld "
|
||||
"at time %lld\n",
|
||||
error, expected_error,
|
||||
(long long)notBefore, (long long )notAfter,
|
||||
(long long)test_time);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_x509_time_tests(CERT_TEST_DATA *tests, size_t ntests, int64_t lower_limit, int64_t upper_limit)
|
||||
{
|
||||
int ret = 0;
|
||||
int failures = 0;
|
||||
X509 *x509 = NULL;
|
||||
X509_STORE_CTX *ctx = NULL;
|
||||
X509_VERIFY_PARAM *vpm = NULL;
|
||||
ASN1_TIME *nb = NULL, *na = NULL;
|
||||
size_t i;
|
||||
|
||||
if ((x509 = X509_new()) == NULL) {
|
||||
TEST_info("Malloc posral se do postele.");
|
||||
goto err;
|
||||
}
|
||||
if ((ctx = X509_STORE_CTX_new()) == NULL) {
|
||||
TEST_info("Malloc posral se do postele.");
|
||||
goto err;
|
||||
}
|
||||
X509_STORE_CTX_init(ctx, NULL, NULL, NULL);
|
||||
if ((vpm = X509_VERIFY_PARAM_new()) == NULL) {
|
||||
TEST_info("Malloc posral se do postele.");
|
||||
goto err;
|
||||
}
|
||||
X509_STORE_CTX_set0_param(ctx, vpm);
|
||||
if ((nb = ASN1_TIME_new()) == NULL) {
|
||||
TEST_info("Malloc posral se do postele.");
|
||||
goto err;
|
||||
}
|
||||
if ((na = ASN1_TIME_new()) == NULL) {
|
||||
TEST_info("Malloc posral se do postele.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < ntests; i++) {
|
||||
int64_t test_time;
|
||||
|
||||
/* Skip this test if any cert values are out of time_t range */
|
||||
if (tests[i].NotBefore < lower_limit || tests[i].NotBefore > upper_limit)
|
||||
continue;
|
||||
if (tests[i].NotAfter < lower_limit || tests[i].NotAfter > upper_limit)
|
||||
continue;
|
||||
|
||||
if (ASN1_TIME_adj(nb, (time_t)tests[i].NotBefore, 0, 0) == NULL) {
|
||||
TEST_info("Could not create NotBefore");
|
||||
goto err;
|
||||
}
|
||||
if (ASN1_TIME_adj(na, (time_t)tests[i].NotAfter, 0, 0) == NULL) {
|
||||
TEST_info("Could not create NotAfter");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Forcibly jam the times into the X509 */
|
||||
if (!X509_set1_notBefore(x509, nb)) {
|
||||
TEST_info("X509_set1_notBefore failed");
|
||||
goto err;
|
||||
}
|
||||
if (!X509_set1_notAfter(x509, na)) {
|
||||
TEST_info("X509_set1_notBefore failed");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Test boundaries of NotBefore */
|
||||
test_time = tests[i].NotBefore - 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = tests[i].NotBefore;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = tests[i].NotBefore + 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
|
||||
/* Test boundaries of NotAfter */
|
||||
test_time = tests[i].NotAfter - 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = tests[i].NotAfter;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = tests[i].NotAfter + 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
|
||||
test_time = 1442939232;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = 1443004020;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
|
||||
test_time = MIN_UTC_TIME;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = MIN_UTC_TIME - 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
|
||||
test_time = MAX_UTC_TIME;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
|
||||
test_time = MAX_UTC_TIME + 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
|
||||
/* Test integer value boundaries */
|
||||
test_time = INT64_MIN;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = INT32_MIN;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = -1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = 0;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = 1;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = INT32_MAX;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = UINT32_MAX;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit, upper_limit);
|
||||
test_time = INT64_MAX;
|
||||
failures += test_a_time(ctx, x509, test_time, tests[i].NotBefore,
|
||||
tests[i].NotAfter, lower_limit,
|
||||
upper_limit);
|
||||
}
|
||||
|
||||
ret = (failures == 0);
|
||||
|
||||
err:
|
||||
X509_STORE_CTX_free(ctx);
|
||||
X509_free(x509);
|
||||
ASN1_STRING_free(nb);
|
||||
ASN1_STRING_free(na);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tests_X509_check_time(void)
|
||||
{
|
||||
/*
|
||||
* time_t sanity checks. We need these until we can evaluate cert
|
||||
* time without depending on platform time_t. Then all this
|
||||
* unpleasantness to decide to not run unit tests that exceed the
|
||||
* range of a platform time_t can go away.
|
||||
*/
|
||||
time_t test_time_t = -1;
|
||||
int time_t_is_unsigned = (test_time_t > 0);
|
||||
int time_t_is_64_bit = (sizeof(time_t) == sizeof(int64_t));
|
||||
int time_t_is_32_bit = (sizeof(time_t) == sizeof(int32_t));
|
||||
|
||||
OPENSSL_assert(time_t_is_32_bit || time_t_is_64_bit);
|
||||
OPENSSL_assert(!time_t_is_unsigned || time_t_is_32_bit);
|
||||
|
||||
if (time_t_is_32_bit) {
|
||||
if (time_t_is_unsigned) {
|
||||
return do_x509_time_tests(cert_test_data, sizeof(cert_test_data) / sizeof(CERT_TEST_DATA),
|
||||
INT32_MIN, INT32_MAX);
|
||||
}
|
||||
else {
|
||||
return do_x509_time_tests(cert_test_data, sizeof(cert_test_data) / sizeof(CERT_TEST_DATA),
|
||||
0, UINT32_MAX);
|
||||
}
|
||||
}
|
||||
return do_x509_time_tests(cert_test_data, sizeof(cert_test_data) / sizeof(CERT_TEST_DATA),
|
||||
INT64_MIN, INT64_MAX);
|
||||
}
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
ADD_TEST(test_standard_exts);
|
||||
ADD_ALL_TESTS(test_a2i_ipaddress, OSSL_NELEM(a2i_ipaddress_tests));
|
||||
ADD_TEST(tests_X509_PURPOSE);
|
||||
ADD_TEST(tests_X509_check_time);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue