ASN1_TIME_SET(3)
β¨ NAME β¨
okay so this is the ASN1_TIME_SET(3) page, and it's literally the whole squad of ASN.1 Time functions. we're talking ASN1_TIME_set, ASN1_UTCTIME_set, ASN1_GENERALIZEDTIME_set, ASN1_TIME_adj, ASN1_UTCTIME_adj, ASN1_GENERALIZEDTIME_adj, ASN1_TIME_set_string, ASN1_TIME_set_string_X509, ASN1_UTCTIME_set_string, ASN1_GENERALIZEDTIME_set_string, ASN1_TIME_normalize, ASN1_TIME_check, ASN1_UTCTIME_check, ASN1_GENERALIZEDTIME_check, ASN1_TIME_print, ASN1_UTCTIME_print, ASN1_GENERALIZEDTIME_print, ASN1_TIME_to_tm, ASN1_TIME_diff, ASN1_TIME_cmp_time_t, ASN1_UTCTIME_cmp_time_t, ASN1_TIME_compare, ASN1_TIME_to_generalizedtime, OPENSSL_gmtime, OPENSSL_timegm, OPENSSL_posix_to_tm, OPENSSL_tm_to_posix β all the ASN.1 Time functions. iykyk π
π SYNOPSIS π
bestie, here's the whole signature lineup, copy-paste exact, no cap:
#include <openssl/asn1.h>
ASN1_TIME *
ASN1_TIME_set(ASN1_TIME *s, time_t t);
ASN1_UTCTIME *
ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t);
ASN1_GENERALIZEDTIME *
ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t);
ASN1_TIME *
ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec);
ASN1_UTCTIME *
ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day,
long offset_sec);
ASN1_GENERALIZEDTIME *
ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t,
int offset_day, long offset_sec);
int
ASN1_TIME_set_string(ASN1_TIME *s, const char *str);
int
ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str);
int
ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
int
ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s,
const char *str);
int
ASN1_TIME_normalize(ASN1_TIME *s);
int
ASN1_TIME_check(const ASN1_TIME *t);
int
ASN1_UTCTIME_check(const ASN1_UTCTIME *t);
int
ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *t);
int
ASN1_TIME_print(BIO *b, const ASN1_TIME *s);
int
ASN1_UTCTIME_print(BIO *b, const ASN1_UTCTIME *s);
int
ASN1_GENERALIZEDTIME_print(BIO *b, const ASN1_GENERALIZEDTIME *s);
int
ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm);
int
ASN1_TIME_diff(int *pday, int *psec, const ASN1_TIME *from,
const ASN1_TIME *to);
int
ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t);
int
ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
int
ASN1_TIME_compare(const ASN1_TIME *s, const ASN1_TIME *t);
ASN1_GENERALIZEDTIME *
ASN1_TIME_to_generalizedtime(const ASN1_TIME *t,
ASN1_GENERALIZEDTIME **out);
and then the crypto/posix besties:
#include <openssl/crypto.h>
struct tm *
OPENSSL_gmtime(const time_t *time, struct tm *out_tm);
#include <openssl/posix_time.h>
int
OPENSSL_timegm(const struct tm *tm, time_t *out_time);
int
OPENSSL_posix_to_tm(int64_t time, struct tm *out_tm);
int
OPENSSL_tm_to_posix(struct tm *t_tm, int64_t *out);
π DESCRIPTION π
okay so picture this: an ASN1_TIME object is basically a shallow wrapper around a string that holds an ASN.1 Time value in the restricted format that's valid in X.509 certificates. it's giving "string but make it cert-legal" π
so an ASN1_TIME object is either an ASN1_UTCTIME object containing a string of the format YYMMDDHHMMSSZ which is valid for the years 1950 to 2049, or an ASN1_GENERALIZEDTIME object containing a string of the format YYYYMMDDHHMMSSZ which is valid for the years 0000 to 1949 and 2050 to 9999. in both cases, the mandatory suffix Z represents the GMT time zone.
LibreSSL by design does not support the full syntax of ASN.1 times. in particular, it neither supports fractional seconds nor any other time zone. so don't come for her with your fancy nanoseconds, bestie π
now the functions, let's go:
ASN1_TIME_set(),ASN1_UTCTIME_set(), andASN1_GENERALIZEDTIME_set()β set the time objectsto the time represented by thetime_tvaluet. ifsisNULL, a new time object is allocated and returned. iconic.ASN1_TIME_adj(),ASN1_UTCTIME_adj(), andASN1_GENERALIZEDTIME_adj()β set the time objectsto the time represented by the timeoffset_dayandoffset_secafter thetime_tvaluet. the values ofoffset_dayoroffset_seccan be negative to set a time beforet. theoffset_secvalue can also exceed the number of seconds in a day. ifsisNULL, a new time object is allocated and returned. flexible queen.ASN1_TIME_adj()may change the type fromASN1_GENERALIZEDTIMEtoASN1_UTCTIMEor vice versa depending on the resulting year. the functionsASN1_UTCTIME_adj()andASN1_GENERALIZEDTIME_adj()do not modify the type of the return object. so know the difference, bestie.ASN1_TIME_set_string(),ASN1_TIME_set_string_X509(),ASN1_UTCTIME_set_string(), andASN1_GENERALIZEDTIME_set_string()β set the time objectsto the time stringstr, which must be in appropriate ASN.1 time format:YYMMDDHHMMSSZforASN1_UTCTIME,YYYYMMDDHHMMSSZforASN1_GENERALIZEDTIME, or either of the two forASN1_TIME. the stringstris copied intos. ifsisNULL, these functions only perform a format check onstr.- in LibreSSL,
ASN1_TIME_set_string()andASN1_TIME_set_string_X509()behave identically and always set the time object to a valid value to use in an X.509 certificate.ASN1_GENERALIZEDTIME_set_string()may encode a time string that is not valid in an X.509 certificate. so watch out for that one π ASN1_TIME_normalize()β converts anASN1_GENERALIZEDTIMEinto a time value that can be used in a certificate by changing it to anASN1_UTCTIMEif possible. it has no effect on anASN1_UTCTIME. glow-up function.ASN1_TIME_check(),ASN1_UTCTIME_check(), andASN1_GENERALIZEDTIME_check()β check the syntax of the time string contained in the objects. vibe check but for time strings β¨ASN1_TIME_print(),ASN1_UTCTIME_print(), andASN1_GENERALIZEDTIME_print()β print out the timesto BIObin human readable format. it will be of the formatMMM DD HH:MM:SS YYYY [GMT], for example"Feb 3 00:55:52 2015 GMT". it does not include a newline. if the time string has an invalid format, it prints out"Bad time value"and returns an error. no cap.ASN1_TIME_to_tm()β converts the timesto the standardtmstructure. ifsisNULL, then the current time is converted. the output time is always in the GMT time zone. thetm_sec,tm_min,tm_hour,tm_mday,tm_mon, andtm_yearfields of thetmstructure are set to the proper values, whereas all other fields are set to0. iftmisNULL, this function performs a format check onsonly. main character energy.ASN1_TIME_diff()β sets*pdayand*psecto the time difference betweenfromandto. iftorepresents a time later thanfrom, then one or both (depending on the time difference) of*pdayand*psecwill be positive. iftorepresents a time earlier thanfrom, then one or both of*pdayand*psecwill be negative. iftoandfromrepresent the same time, then*pdayand*psecwill both be zero. if both*pdayand*psecare nonzero, they will always have the same sign. the value of*psecwill always be less than the number of seconds in a day. iffromortoisNULL, the current time is used. math but make it cute.ASN1_TIME_cmp_time_t(),ASN1_UTCTIME_cmp_time_t(), andASN1_TIME_compare()β compare the two times represented bysandt. who's earlier, who's later, we stan a comparison.ASN1_TIME_to_generalizedtime()β converts theASN1_TIMEtto anASN1_GENERALIZEDTIME, regardless of year. if eitheroutor*outisNULL, then a new object is allocated and must be freed after use. don't forget to free, bestie, or it's a leak π- the
ASN1_TIME,ASN1_UTCTIME, andASN1_GENERALIZEDTIMEobjects are represented asASN1_STRINGobjects internally and can be freed usingASN1_STRING_free(3). periodt. - it is recommended that
ASN1_TIMEfunctions be used instead ofASN1_UTCTIMEorASN1_GENERALIZEDTIMEfunctions because theASN1_UTCTIMEandASN1_GENERALIZEDTIMEfunctions act only on that specific time format, while theASN1_TIMEfunctions operate on either format. so use the flexible one, bestie. OPENSSL_gmtime()β converts atime_tvalue intimeto astruct tminout_tmand also returns the struct passed in on success. slay.OPENSSL_timegm()β converts a time structure in UTC time intmto atime_tvalue inout_time. iconic.OPENSSL_posix_to_tm()β converts anint64_tPOSIX time value intime, which must be in the range of year 0 to 9999, to a broken out time value intm. no pressure.OPENSSL_tm_to_posix()β converts a time value between the years 0 and 9999 intmto a POSIX time value inout. reverse uno card.
π RETURN VALUES π
okay so what do these functions give back? let's break it down:
ASN1_TIME_set(),ASN1_UTCTIME_set(),ASN1_GENERALIZEDTIME_set(),ASN1_TIME_adj(),ASN1_UTCTIME_adj(),ASN1_GENERALIZEDTIME_adj(), andASN1_TIME_to_generalizedtime()return a pointer to a time object orNULLif an error occurred. no vibes on error.ASN1_TIME_set_string(),ASN1_TIME_set_string_X509(),ASN1_UTCTIME_set_string(), andASN1_GENERALIZEDTIME_set_string()return1if the time value is successfully set or0otherwise. simple.ASN1_TIME_normalize()returns1on success or0on error. glow-up successful or not.ASN1_TIME_check(),ASN1_UTCTIME_check(), andASN1_GENERALIZEDTIME_check()return1if the time string contained in the object is syntactically correct or0otherwise. vibe check passed or failed.ASN1_TIME_print(),ASN1_UTCTIME_print(), andASN1_GENERALIZEDTIME_print()return1if the time is successfully printed or0if an error occurred (I/O error or invalid time format). so if it says "Bad time value", you already know it's a 0.ASN1_TIME_to_tm()returns1if the time is successfully parsed or0if an error occurred, usually due to an invalid time format. bestie, format matters.ASN1_TIME_diff()returns1for success or0for failure. it can for example fail if a time string passed in has invalid syntax. math can fail, apparently.ASN1_TIME_cmp_time_t(),ASN1_UTCTIME_cmp_time_t(), andASN1_TIME_compare()return-1ifsis earlier thant,0if both are equal,1ifsis later thant, or-2on error. so-2is the error vibe.OPENSSL_timegm()returns1for success or0for failure. it can fail if the time is not representable in atime_t, or falls outside the range allowed in RFC 5280 times. tragic.OPENSSL_gmtime()returnsout_tmon success orNULLfor failure. it can fail if the time is not representable in astruct tm, or falls outside the range allowed in RFC 5280 times. same energy.OPENSSL_posix_to_tm()andOPENSSL_tm_to_posix()return1for success or0on failure. it is a failure if the year is less than0or more than9999. so keep it in range, bestie.
π¦ EXAMPLES π¦
set a time object to one hour after the current time and print it out, periodt:
#include <time.h>
#include <openssl/asn1.h>
ASN1_TIME *asn1_time;
time_t t;
BIO *b;
t = time(NULL);
asn1_time = ASN1_TIME_adj(NULL, t, 0, 60 * 60);
b = BIO_new_fp(stdout, BIO_NOCLOSE);
if (asn1_time != NULL) {
ASN1_TIME_print(b, asn1_time);
BIO_printf(b, "\n");
} else {
BIO_printf(b, "Time out of range or un-representable\n");
}
ASN1_STRING_free(asn1_time);
BIO_free(b);
πΈ SEE ALSO πΈ
π STANDARDS π
the usage of the ASN.1 Time, UTCTime, and GeneralizedTime data types in X.509 certificates is specified in RFC 5280, Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile, section 4.1.2.5 (TBS Certificate Validity). that's the standard, bestie β¨
π°οΈ HISTORY π°οΈ
okay bestie, storytime πβ¨ β this is literally the family tree of every function on this page and it goes way back. Buckle up π
ASN1_UTCTIME_check()andASN1_UTCTIME_print()β the OGs π§ first showed up in SSLeay 0.5.1.ASN1_UTCTIME_set()β debuted in SSLeay 0.6.0.ASN1_UTCTIME_set_string()β arrived in SSLeay 0.9.0.- and all of those geriatric icons π have been available since OpenBSD 2.4.
ASN1_TIME_set(),ASN1_GENERALIZEDTIME_set(),ASN1_GENERALIZEDTIME_set_string(),ASN1_GENERALIZEDTIME_check(),ASN1_TIME_print(), andASN1_GENERALIZEDTIME_print()β this whole friend group π«Ά first appeared in OpenSSL 0.9.2b and has been available since OpenBSD 2.6.ASN1_UTCTIME_cmp_time_t()β first appeared in OpenSSL 0.9.6, available since OpenBSD 2.9.ASN1_TIME_check()andASN1_TIME_to_generalizedtime()β first appeared in OpenSSL 0.9.7, available since OpenBSD 3.2.ASN1_TIME_adj(),ASN1_UTCTIME_adj(),ASN1_GENERALIZEDTIME_adj(), andASN1_TIME_set_string()β first appeared in OpenSSL 1.0.0, available since OpenBSD 4.9.ASN1_TIME_diff()β first appeared in OpenSSL 1.0.2, available since OpenBSD 7.1.ASN1_TIME_set_string_X509(),ASN1_TIME_normalize(),ASN1_TIME_to_tm(),ASN1_TIME_cmp_time_t(), andASN1_TIME_compare()β first appeared in OpenSSL 1.1.1, available since OpenBSD 7.2. (newer gen, still iconic π)OPENSSL_gmtime()β first appeared in OpenSSL 0.9.7. ThenOPENSSL_timegm(),OPENSSL_posix_to_tm(), andOPENSSL_tm_to_posix()first appeared in BoringSSL π β and all these functions have been available since OpenBSD 7.5.
β οΈ CAVEATS β οΈ
okay this is the part where you listen ππ no playing on your phone.
Some applications out here doing the absolute most π β they add offset times directly to a time_t value and then pass the results to ASN1_TIME_set() (or equivalent). And yeahβ¦ that can cause problems, because the time_t value can overflow on some systems, resulting in unexpected results. π Not the vibe!
New applications should useASN1_TIME_adj()instead π«Ά β pass the offset value in theoffset_secandoffset_dayparameters instead of directly manipulating atime_tvalue. fr fr, do it this way. πΈ
that's the whole page bestie, you ate it up πβ¨ go forth and set those times responsibly π
πΈ this one's from Debian, dated March 5, 2024 β and the page is literally called ASN1_TIME_SET(3). periodt. π
π
π¦ where this page comes from
- opensuse-leap 16.0: libressl-devel-doc 4.1.0-bp160.1.1 Β· OpenSSL
- Copyright (c) 2022 Ingo Schwarze <schwarze@openbsd.org>
- Copyright (c) 2022 Bob Beck <beck@openbsd.org>
- Copyright (c) 2015, 2017 The OpenSSL Project. All rights reserved
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms