From 25d7cd1d69e5d5df9c9f346922a48797baca03b7 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Fri, 22 Nov 2019 13:02:52 +0100 Subject: [PATCH] add X509_cmp_timeframe() including its documentation Reviewed-by: Paul Dale Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10502) --- crypto/x509/x509_vfy.c | 25 ++++++++++++ crypto/x509/x509_vpm.c | 2 +- doc/man3/X509_VERIFY_PARAM_set_flags.pod | 2 +- doc/man3/X509_cmp_time.pod | 34 +++++++++++++--- include/openssl/x509.h | 2 + include/openssl/x509_vfy.h | 2 +- test/x509_time_test.c | 51 ++++++++++++++++++++++++ util/libcrypto.num | 1 + 8 files changed, 110 insertions(+), 9 deletions(-) diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 1e2e4cd557..c8d1258803 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -1851,6 +1851,31 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) return ret; } +/* + * Return 0 if time should not be checked or reference time is in range, + * or else 1 if it is past the end, or -1 if it is before the start + */ +int X509_cmp_timeframe(const X509_VERIFY_PARAM *vpm, + const ASN1_TIME *start, const ASN1_TIME *end) +{ + time_t ref_time; + time_t *time = NULL; + unsigned long flags = vpm == NULL ? 0 : X509_VERIFY_PARAM_get_flags(vpm); + + if ((flags & X509_V_FLAG_USE_CHECK_TIME) != 0) { + ref_time = X509_VERIFY_PARAM_get_time(vpm); + time = &ref_time; + } else if ((flags & X509_V_FLAG_NO_CHECK_TIME) != 0) { + return 0; /* this means ok */ + } /* else reference time is the current time */ + + if (end != NULL && X509_cmp_time(end, time) < 0) + return 1; + if (start != NULL && X509_cmp_time(start, time) > 0) + return -1; + return 0; +} + ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj) { return X509_time_adj(s, adj, NULL); diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c index 782fa136f2..27156b9b4d 100644 --- a/crypto/x509/x509_vpm.c +++ b/crypto/x509/x509_vpm.c @@ -282,7 +282,7 @@ int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, return 1; } -unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param) +unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param) { return param->flags; } diff --git a/doc/man3/X509_VERIFY_PARAM_set_flags.pod b/doc/man3/X509_VERIFY_PARAM_set_flags.pod index 2d161ebbab..8352a39b86 100644 --- a/doc/man3/X509_VERIFY_PARAM_set_flags.pod +++ b/doc/man3/X509_VERIFY_PARAM_set_flags.pod @@ -26,7 +26,7 @@ X509_VERIFY_PARAM_set1_ip_asc unsigned long flags); int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags); - unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); + unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param); int X509_VERIFY_PARAM_set_inh_flags(X509_VERIFY_PARAM *param, uint32_t flags); diff --git a/doc/man3/X509_cmp_time.pod b/doc/man3/X509_cmp_time.pod index 6fbb66f1c2..73ef9e3fbc 100644 --- a/doc/man3/X509_cmp_time.pod +++ b/doc/man3/X509_cmp_time.pod @@ -2,13 +2,16 @@ =head1 NAME -X509_cmp_time, X509_cmp_current_time, X509_time_adj, X509_time_adj_ex +X509_cmp_time, X509_cmp_current_time, X509_cmp_timeframe, +X509_time_adj, X509_time_adj_ex - X509 time functions =head1 SYNOPSIS int X509_cmp_time(const ASN1_TIME *asn1_time, time_t *in_tm); int X509_cmp_current_time(const ASN1_TIME *asn1_time); + int X509_cmp_timeframe(const X509_VERIFY_PARAM *vpm, + const ASN1_TIME *start, const ASN1_TIME *end); ASN1_TIME *X509_time_adj(ASN1_TIME *asn1_time, long offset_sec, time_t *in_tm); ASN1_TIME *X509_time_adj_ex(ASN1_TIME *asn1_time, int offset_day, long offset_sec, time_t *in_tm); @@ -16,10 +19,14 @@ X509_cmp_time, X509_cmp_current_time, X509_time_adj, X509_time_adj_ex =head1 DESCRIPTION X509_cmp_time() compares the ASN1_TIME in B with the time -in . X509_cmp_current_time() compares the ASN1_TIME in -B with the current time, expressed as time_t. B -must satisfy the ASN1_TIME format mandated by RFC 5280, i.e., its -format must be either YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ. +in . + +X509_cmp_current_time() compares the ASN1_TIME in +B with the current time, expressed as time_t. + +X509_cmp_timeframe() compares the given time period with the reference time +included in the verification parameters B if they are not NULL and contain +B; else the current time is used as reference time. X509_time_adj_ex() sets the ASN1_TIME structure B to the time B and B after B. @@ -35,6 +42,9 @@ is allocated and returned. In all methods, if B is NULL, the current time, expressed as time_t, is used. +B must satisfy the ASN1_TIME format mandated by RFC 5280, +i.e., its format must be either YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ. + =head1 BUGS Unlike many standard comparison functions, X509_cmp_time() and @@ -43,12 +53,24 @@ X509_cmp_current_time() return 0 on error. =head1 RETURN VALUES X509_cmp_time() and X509_cmp_current_time() return -1 if B -is earlier than, or equal to, B (resp. current time), and 1 +is earlier than, or equal to, B (resp. current time), and 1 otherwise. These methods return 0 on error. +X509_cmp_timeframe() returns 0 if B is not NULL and the verification +parameters do not contain B +but do contain B. Otherwise it returns +1 if the end time is not NULL and the reference time (which has determined as +stated above) is past the end time, -1 if the start time is not NULL and the +reference time is before, else 0 to indicate that the reference time is in range +(implying that the end time is not before the start time if both are present). + X509_time_adj() and X509_time_adj_ex() return a pointer to the updated ASN1_TIME structure, and NULL on error. +=head1 HISTORY + +X509_cmp_timeframe() was added in OpenSSL 3.0. + =head1 COPYRIGHT Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. diff --git a/include/openssl/x509.h b/include/openssl/x509.h index e4de10e6f9..9d8cc03c53 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -495,6 +495,8 @@ DECLARE_ASN1_DUP_FUNCTION(X509_NAME_ENTRY) int X509_cmp_time(const ASN1_TIME *s, time_t *t); int X509_cmp_current_time(const ASN1_TIME *s); +int X509_cmp_timeframe(const X509_VERIFY_PARAM *vpm, + const ASN1_TIME *start, const ASN1_TIME *end); ASN1_TIME *X509_time_adj(ASN1_TIME *s, long adj, time_t *t); ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec, time_t *t); diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h index 651ffbcbe6..affdc67d80 100644 --- a/include/openssl/x509_vfy.h +++ b/include/openssl/x509_vfy.h @@ -558,7 +558,7 @@ int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags); int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags); -unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); +unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param); int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); diff --git a/test/x509_time_test.c b/test/x509_time_test.c index 79c23cf5b3..8e813cb0f9 100644 --- a/test/x509_time_test.c +++ b/test/x509_time_test.c @@ -297,6 +297,56 @@ static int test_x509_cmp_time_current(void) return failed == 0; } +static int test_X509_cmp_timeframe_vpm(const X509_VERIFY_PARAM *vpm, + ASN1_TIME *asn1_before, + ASN1_TIME *asn1_mid, + ASN1_TIME *asn1_after) +{ + int always_0 = vpm != NULL + && (X509_VERIFY_PARAM_get_flags(vpm) & X509_V_FLAG_USE_CHECK_TIME) == 0 + && (X509_VERIFY_PARAM_get_flags(vpm) & X509_V_FLAG_NO_CHECK_TIME) != 0; + + return asn1_before != NULL && asn1_mid != NULL && asn1_after != NULL + && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_before, asn1_after), 0) + && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_before, NULL), 0) + && TEST_int_eq(X509_cmp_timeframe(vpm, NULL, asn1_after), 0) + && TEST_int_eq(X509_cmp_timeframe(vpm, NULL, NULL), 0) + && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_after, asn1_after), + always_0 ? 0 : -1) + && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_before, asn1_before), + always_0 ? 0 : 1) + && TEST_int_eq(X509_cmp_timeframe(vpm, asn1_after, asn1_before), + always_0 ? 0 : 1); +} + +static int test_X509_cmp_timeframe(void) +{ + time_t now = time(NULL); + ASN1_TIME *asn1_mid = ASN1_TIME_adj(NULL, now, 0, 0); + /* Pick a day earlier and later, relative to any system clock. */ + ASN1_TIME *asn1_before = ASN1_TIME_adj(NULL, now, -1, 0); + ASN1_TIME *asn1_after = ASN1_TIME_adj(NULL, now, 1, 0); + X509_VERIFY_PARAM *vpm = X509_VERIFY_PARAM_new(); + int res; + + res = vpm != NULL + && test_X509_cmp_timeframe_vpm(NULL, asn1_before, asn1_mid, asn1_after) + && test_X509_cmp_timeframe_vpm(vpm, asn1_before, asn1_mid, asn1_after); + + X509_VERIFY_PARAM_set_time(vpm, now); + res = res + && test_X509_cmp_timeframe_vpm(vpm, asn1_before, asn1_mid, asn1_after) + && X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME) + && test_X509_cmp_timeframe_vpm(vpm, asn1_before, asn1_mid, asn1_after); + + X509_VERIFY_PARAM_free(vpm); + ASN1_TIME_free(asn1_mid); + ASN1_TIME_free(asn1_before); + ASN1_TIME_free(asn1_after); + + return res; +} + static int test_x509_time(int idx) { ASN1_TIME *t = NULL; @@ -485,6 +535,7 @@ static int test_x509_time_print(int idx) int setup_tests(void) { ADD_TEST(test_x509_cmp_time_current); + ADD_TEST(test_X509_cmp_timeframe); ADD_ALL_TESTS(test_x509_cmp_time, OSSL_NELEM(x509_cmp_tests)); ADD_ALL_TESTS(test_x509_time, OSSL_NELEM(x509_format_tests)); ADD_ALL_TESTS(test_days, OSSL_NELEM(day_of_week_tests)); diff --git a/util/libcrypto.num b/util/libcrypto.num index 32b502147c..0553f88859 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4909,3 +4909,4 @@ i2d_X509_PUBKEY_fp ? 3_0_0 EXIST::FUNCTION:STDIO d2i_X509_PUBKEY_bio ? 3_0_0 EXIST::FUNCTION: i2d_X509_PUBKEY_bio ? 3_0_0 EXIST::FUNCTION: RSA_get0_pss_params ? 3_0_0 EXIST::FUNCTION:RSA +X509_cmp_timeframe ? 3_0_0 EXIST::FUNCTION: -- 2.25.1