mirror of https://github.com/wolfSSL/wolfssl.git
Merge pull request #11228 from aidangarske/fenrir-fixes-9961
Encode default cert validity as UTCTime through 2049pull/11090/head
commit
94dca6fdd4
|
|
@ -520,25 +520,25 @@ int test_wolfSSL_X509_sign(void)
|
|||
* with the MSB set. See GenerateInteger in asn.c */
|
||||
#ifndef USE_CERT_BUFFERS_1024
|
||||
#ifndef WOLFSSL_ALT_NAMES
|
||||
/* Valid case - size should be 781-786 with 16 byte serial number */
|
||||
ExpectTrue((781 + snSz <= ret) && (ret <= 781 + 5 + snSz));
|
||||
/* Valid case - size should be 777-782 with 16 byte serial number */
|
||||
ExpectTrue((777 + snSz <= ret) && (ret <= 777 + 5 + snSz));
|
||||
#elif defined(WOLFSSL_IP_ALT_NAME)
|
||||
/* Valid case - size should be 955-960 with 16 byte serial number */
|
||||
ExpectTrue((939 + snSz <= ret) && (ret <= 939 + 5 + snSz));
|
||||
/* Valid case - size should be 951-956 with 16 byte serial number */
|
||||
ExpectTrue((935 + snSz <= ret) && (ret <= 935 + 5 + snSz));
|
||||
#else
|
||||
/* Valid case - size should be 926-931 with 16 byte serial number */
|
||||
ExpectTrue((910 + snSz <= ret) && (ret <= 910 + 5 + snSz));
|
||||
/* Valid case - size should be 922-927 with 16 byte serial number */
|
||||
ExpectTrue((906 + snSz <= ret) && (ret <= 906 + 5 + snSz));
|
||||
#endif
|
||||
#else
|
||||
#ifndef WOLFSSL_ALT_NAMES
|
||||
/* Valid case - size should be 537-542 with 16 byte serial number */
|
||||
ExpectTrue((521 + snSz <= ret) && (ret <= 521 + 5 + snSz));
|
||||
/* Valid case - size should be 533-538 with 16 byte serial number */
|
||||
ExpectTrue((517 + snSz <= ret) && (ret <= 517 + 5 + snSz));
|
||||
#elif defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
|
||||
/* Valid case - size should be 695-670 with 16 byte serial number */
|
||||
ExpectTrue((679 + snSz <= ret) && (ret <= 679 + 5 + snSz));
|
||||
/* Valid case - size should be 691-696 with 16 byte serial number */
|
||||
ExpectTrue((675 + snSz <= ret) && (ret <= 675 + 5 + snSz));
|
||||
#else
|
||||
/* Valid case - size should be 666-671 with 16 byte serial number */
|
||||
ExpectTrue((650 + snSz <= ret) && (ret <= 650 + 5 + snSz));
|
||||
/* Valid case - size should be 662-667 with 16 byte serial number */
|
||||
ExpectTrue((646 + snSz <= ret) && (ret <= 646 + 5 + snSz));
|
||||
#endif
|
||||
#endif
|
||||
/* check that issuer name is as expected after signature */
|
||||
|
|
|
|||
|
|
@ -28300,15 +28300,32 @@ static WC_INLINE byte itob(int number)
|
|||
}
|
||||
|
||||
|
||||
/* write time to output, format */
|
||||
static void SetTime(struct tm* date, byte* output)
|
||||
/* RFC 5280: validity dates through 2049 encode as UTCTime, 2050 and later as
|
||||
* GeneralizedTime. date->tm_year holds the full year here. */
|
||||
static byte ValidityTimeFormat(const struct tm* date)
|
||||
{
|
||||
if (date->tm_year >= 1950 && date->tm_year < 2050)
|
||||
return ASN_UTC_TIME;
|
||||
return ASN_GENERALIZED_TIME;
|
||||
}
|
||||
|
||||
/* write time value to output in the given ASN.1 format */
|
||||
static void SetTime(struct tm* date, byte* output, byte format)
|
||||
{
|
||||
int i = 0;
|
||||
int year = date->tm_year;
|
||||
|
||||
output[i++] = itob((date->tm_year % 10000) / 1000);
|
||||
output[i++] = itob((date->tm_year % 1000) / 100);
|
||||
output[i++] = itob((date->tm_year % 100) / 10);
|
||||
output[i++] = itob( date->tm_year % 10);
|
||||
if (format == ASN_UTC_TIME) {
|
||||
year %= 100;
|
||||
output[i++] = itob((year / 10) % 10);
|
||||
output[i++] = itob( year % 10);
|
||||
}
|
||||
else {
|
||||
output[i++] = itob((year % 10000) / 1000);
|
||||
output[i++] = itob((year % 1000) / 100);
|
||||
output[i++] = itob((year % 100) / 10);
|
||||
output[i++] = itob( year % 10);
|
||||
}
|
||||
|
||||
output[i++] = itob(date->tm_mon / 10);
|
||||
output[i++] = itob(date->tm_mon % 10);
|
||||
|
|
@ -30071,6 +30088,8 @@ static int SetValidity(byte* before, byte* after, int daysValid)
|
|||
{
|
||||
#ifndef NO_ASN_TIME
|
||||
int ret = 0;
|
||||
byte format;
|
||||
word32 timeSz;
|
||||
time_t now;
|
||||
time_t then;
|
||||
struct tm* tmpTime;
|
||||
|
|
@ -30101,7 +30120,12 @@ static int SetValidity(byte* before, byte* after, int daysValid)
|
|||
localTime.tm_year += 1900;
|
||||
localTime.tm_mon += 1;
|
||||
|
||||
SetTime(&localTime, before);
|
||||
format = ValidityTimeFormat(&localTime);
|
||||
timeSz = (format == ASN_UTC_TIME) ? ASN_UTC_TIME_SIZE - 1
|
||||
: ASN_GEN_TIME_SZ;
|
||||
before[0] = format;
|
||||
SetLength(timeSz, before + 1);
|
||||
SetTime(&localTime, before + 2, format);
|
||||
|
||||
/* add daysValid of seconds */
|
||||
then = now + (daysValid * (time_t)86400);
|
||||
|
|
@ -30118,7 +30142,12 @@ static int SetValidity(byte* before, byte* after, int daysValid)
|
|||
localTime.tm_year += 1900;
|
||||
localTime.tm_mon += 1;
|
||||
|
||||
SetTime(&localTime, after);
|
||||
format = ValidityTimeFormat(&localTime);
|
||||
timeSz = (format == ASN_UTC_TIME) ? ASN_UTC_TIME_SIZE - 1
|
||||
: ASN_GEN_TIME_SZ;
|
||||
after[0] = format;
|
||||
SetLength(timeSz, after + 1);
|
||||
SetTime(&localTime, after + 2, format);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -30811,6 +30840,8 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
|
|||
int ret = 0;
|
||||
word32 issRawLen = 0;
|
||||
word32 sbjRawLen = 0;
|
||||
byte localBefore[MAX_DATE_SIZE];
|
||||
byte localAfter[MAX_DATE_SIZE];
|
||||
|
||||
/* Unused without PQC */
|
||||
(void)falconKey;
|
||||
|
|
@ -31036,16 +31067,35 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* Don't put out UTC before data. */
|
||||
dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_UTC].noOut = 1;
|
||||
/* Make space for before date data. */
|
||||
SetASN_Buffer(&dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_GT],
|
||||
NULL, ASN_GEN_TIME_SZ);
|
||||
/* Don't put out UTC after data. */
|
||||
dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_UTC].noOut = 1;
|
||||
/* Make space for after date data. */
|
||||
SetASN_Buffer(&dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_GT],
|
||||
NULL, ASN_GEN_TIME_SZ);
|
||||
/* Compute default validity dates; SetValidity picks UTCTime or
|
||||
* Generalized Time per RFC 5280 based on the year. */
|
||||
ret = SetValidity(localBefore, localAfter, cert->daysValid);
|
||||
if (ret == 0) {
|
||||
if (localBefore[0] == ASN_UTC_TIME) {
|
||||
SetASN_Buffer(
|
||||
&dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_UTC],
|
||||
localBefore + 2, ASN_UTC_TIME_SIZE - 1);
|
||||
dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_GT].noOut = 1;
|
||||
}
|
||||
else {
|
||||
dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_UTC].noOut = 1;
|
||||
SetASN_Buffer(
|
||||
&dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_GT],
|
||||
localBefore + 2, ASN_GEN_TIME_SZ);
|
||||
}
|
||||
if (localAfter[0] == ASN_UTC_TIME) {
|
||||
SetASN_Buffer(
|
||||
&dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_UTC],
|
||||
localAfter + 2, ASN_UTC_TIME_SIZE - 1);
|
||||
dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_GT].noOut = 1;
|
||||
}
|
||||
else {
|
||||
dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_UTC].noOut = 1;
|
||||
SetASN_Buffer(
|
||||
&dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_GT],
|
||||
localAfter + 2, ASN_GEN_TIME_SZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sbjRawLen > 0) {
|
||||
/* Put in encoded subject name. */
|
||||
|
|
@ -31083,7 +31133,9 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
|
|||
X509CERTASN_IDX_SIGNATURE);
|
||||
|
||||
/* Calculate encoded certificate body size. */
|
||||
ret = SizeASN_Items(x509CertASN, dataASN, x509CertASN_Length, &sz);
|
||||
if (ret >= 0) {
|
||||
ret = SizeASN_Items(x509CertASN, dataASN, x509CertASN_Length, &sz);
|
||||
}
|
||||
}
|
||||
/* Check buffer is big enough for encoded data. */
|
||||
if ((ret == 0) && (sz > derSz)) {
|
||||
|
|
@ -31114,18 +31166,6 @@ static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz,
|
|||
dataASN[X509CERTASN_IDX_TBS_SUBJECT_SEQ].data.buffer.length,
|
||||
&cert->subject, cert->heap);
|
||||
}
|
||||
if (ret >= 0) {
|
||||
if (cert->beforeDateSz == 0 || cert->afterDateSz == 0)
|
||||
{
|
||||
/* Encode validity into buffer. */
|
||||
/* safe casts -- the pointers are actually inside derBuffer. */
|
||||
ret = SetValidity(
|
||||
(byte*)(wc_ptr_t)dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTB_GT]
|
||||
.data.buffer.data,
|
||||
(byte*)(wc_ptr_t)dataASN[X509CERTASN_IDX_TBS_VALIDITY_NOTA_GT]
|
||||
.data.buffer.data, cert->daysValid);
|
||||
}
|
||||
}
|
||||
if (ret >= 0) {
|
||||
/* Encode public key into buffer. */
|
||||
/* safe cast -- the pointer is actually inside derBuffer. */
|
||||
|
|
|
|||
|
|
@ -5911,10 +5911,6 @@ int SetNameEx(byte* output, word32 outputSz, CertName* name, void* heap)
|
|||
|
||||
/* Set Date validity from now until now + daysValid
|
||||
* return size in bytes written to output, 0 on error */
|
||||
/* TODO https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.5
|
||||
* "MUST always encode certificate validity dates through the year 2049 as
|
||||
* UTCTime; certificate validity dates in 2050 or later MUST be encoded as
|
||||
* GeneralizedTime." */
|
||||
static int SetValidity(byte* output, int daysValid)
|
||||
{
|
||||
#ifndef NO_ASN_TIME
|
||||
|
|
@ -5922,6 +5918,8 @@ static int SetValidity(byte* output, int daysValid)
|
|||
byte after[MAX_DATE_SIZE];
|
||||
|
||||
word32 beforeSz, afterSz, seqSz;
|
||||
word32 timeSz;
|
||||
byte format;
|
||||
|
||||
time_t now;
|
||||
time_t then;
|
||||
|
|
@ -5941,9 +5939,6 @@ static int SetValidity(byte* output, int daysValid)
|
|||
now = wc_Time(0);
|
||||
|
||||
/* before now */
|
||||
before[0] = ASN_GENERALIZED_TIME;
|
||||
beforeSz = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1; /* gen tag */
|
||||
|
||||
/* subtract 1 day of seconds for more compliance */
|
||||
then = now - 86400;
|
||||
expandedTime = XGMTIME(&then, tmpTime);
|
||||
|
|
@ -5957,11 +5952,13 @@ static int SetValidity(byte* output, int daysValid)
|
|||
localTime.tm_year += 1900;
|
||||
localTime.tm_mon += 1;
|
||||
|
||||
SetTime(&localTime, before + beforeSz);
|
||||
beforeSz += ASN_GEN_TIME_SZ;
|
||||
|
||||
after[0] = ASN_GENERALIZED_TIME;
|
||||
afterSz = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1; /* gen tag */
|
||||
format = ValidityTimeFormat(&localTime);
|
||||
timeSz = (format == ASN_UTC_TIME) ? ASN_UTC_TIME_SIZE - 1
|
||||
: ASN_GEN_TIME_SZ;
|
||||
before[0] = format;
|
||||
beforeSz = SetLength(timeSz, before + 1) + 1;
|
||||
SetTime(&localTime, before + beforeSz, format);
|
||||
beforeSz += timeSz;
|
||||
|
||||
/* add daysValid of seconds */
|
||||
then = now + (daysValid * (time_t)86400);
|
||||
|
|
@ -5976,8 +5973,13 @@ static int SetValidity(byte* output, int daysValid)
|
|||
localTime.tm_year += 1900;
|
||||
localTime.tm_mon += 1;
|
||||
|
||||
SetTime(&localTime, after + afterSz);
|
||||
afterSz += ASN_GEN_TIME_SZ;
|
||||
format = ValidityTimeFormat(&localTime);
|
||||
timeSz = (format == ASN_UTC_TIME) ? ASN_UTC_TIME_SIZE - 1
|
||||
: ASN_GEN_TIME_SZ;
|
||||
after[0] = format;
|
||||
afterSz = SetLength(timeSz, after + 1) + 1;
|
||||
SetTime(&localTime, after + afterSz, format);
|
||||
afterSz += timeSz;
|
||||
|
||||
/* headers and output */
|
||||
seqSz = SetSequence(beforeSz + afterSz, output);
|
||||
|
|
|
|||
|
|
@ -30821,6 +30821,120 @@ exit_rsa_even_mod:
|
|||
#endif /* WOLFSSL_HAVE_SP_RSA */
|
||||
|
||||
#if defined(WOLFSSL_CERT_GEN) && !defined(NO_ASN_TIME) && !defined(WOLFSSL_NO_MALLOC)
|
||||
#ifdef WOLFSSL_TEST_CERT
|
||||
/* RFC 5280: validity dates through 2049 encode as UTCTime, 2050 and later as
|
||||
* GeneralizedTime. Returns 0 when the decoded date TLV honors that rule. */
|
||||
static int cert_time_format_ok(const byte* dateTLV)
|
||||
{
|
||||
int year;
|
||||
|
||||
if (dateTLV == NULL)
|
||||
return -1;
|
||||
if (dateTLV[0] == ASN_UTC_TIME)
|
||||
return 0;
|
||||
if (dateTLV[0] != ASN_GENERALIZED_TIME)
|
||||
return -1;
|
||||
year = (dateTLV[2] - '0') * 1000 + (dateTLV[3] - '0') * 100 +
|
||||
(dateTLV[4] - '0') * 10 + (dateTLV[5] - '0');
|
||||
return ((year < 1950) || (year >= 2050)) ? 0 : -1;
|
||||
}
|
||||
|
||||
/* Decode the calendar year from an ASN.1 date TLV, inverting the two-digit
|
||||
* UTCTime year, so a wrong encoded year is caught. Returns -1 on error. */
|
||||
static int cert_date_year(const byte* dateTLV)
|
||||
{
|
||||
int yy;
|
||||
|
||||
if (dateTLV == NULL)
|
||||
return -1;
|
||||
if (dateTLV[0] == ASN_UTC_TIME) {
|
||||
yy = (dateTLV[2] - '0') * 10 + (dateTLV[3] - '0');
|
||||
return (yy < 50) ? 2000 + yy : 1900 + yy;
|
||||
}
|
||||
if (dateTLV[0] == ASN_GENERALIZED_TIME) {
|
||||
return (dateTLV[2] - '0') * 1000 + (dateTLV[3] - '0') * 100 +
|
||||
(dateTLV[4] - '0') * 10 + (dateTLV[5] - '0');
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static time_t certGenBoundaryTime;
|
||||
static time_t cert_gen_boundary_time_cb(time_t* t)
|
||||
{
|
||||
if (t != NULL)
|
||||
*t = certGenBoundaryTime;
|
||||
return certGenBoundaryTime;
|
||||
}
|
||||
|
||||
/* Deterministically exercise the RFC 5280 UTCTime/GeneralizedTime boundary by
|
||||
* forcing the clock to fixed mid-2049 and mid-2050 dates. Those epochs need a
|
||||
* 64-bit time_t, so 32-bit-time_t builds skip the check. */
|
||||
static wc_test_ret_t cert_gen_time_boundary_test(Cert* cert, byte* der,
|
||||
RsaKey* key, WC_RNG* rng, DecodedCert* decode)
|
||||
{
|
||||
static const struct {
|
||||
time_t now;
|
||||
int daysValid;
|
||||
byte beforeTag;
|
||||
byte afterTag;
|
||||
int beforeYear;
|
||||
int afterYear;
|
||||
} cases[] = {
|
||||
{ (time_t)2508710400UL, 100, ASN_UTC_TIME, ASN_UTC_TIME,
|
||||
2049, 2049 },
|
||||
{ (time_t)2540246400UL, 100, ASN_GENERALIZED_TIME, ASN_GENERALIZED_TIME,
|
||||
2050, 2050 },
|
||||
{ (time_t)2508710400UL, 400, ASN_UTC_TIME, ASN_GENERALIZED_TIME,
|
||||
2049, 2050 }
|
||||
};
|
||||
wc_test_ret_t ret = 0;
|
||||
int tSz = (int)sizeof(time_t);
|
||||
int tSigned = ((time_t)-1 < 0);
|
||||
int certSz;
|
||||
int i;
|
||||
|
||||
/* The mid-2050 epoch needs a time_t that reaches past 2038: 64-bit, or
|
||||
* unsigned 32-bit (good to 2106). Signed 32-bit cannot, so skip it. */
|
||||
if ((tSz < 8) && tSigned)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
|
||||
certGenBoundaryTime = cases[i].now;
|
||||
ret = wc_SetTimeCb(cert_gen_boundary_time_cb);
|
||||
if (ret != 0)
|
||||
return WC_TEST_RET_ENC_EC(ret);
|
||||
|
||||
cert->daysValid = cases[i].daysValid;
|
||||
ret = 0;
|
||||
WC_TEST_RSA_ASYNC_DO(&key->asyncDev,
|
||||
wc_MakeSelfCert(cert, der, FOURK_BUF, key, rng));
|
||||
(void)wc_SetTimeCb(NULL);
|
||||
if (ret < 0)
|
||||
return WC_TEST_RET_ENC_EC(ret);
|
||||
certSz = (int)ret;
|
||||
|
||||
InitDecodedCert(decode, der, certSz, HEAP_HINT);
|
||||
ret = ParseCert(decode, CERT_TYPE, NO_VERIFY, 0);
|
||||
if (ret == 0) {
|
||||
if ((decode->beforeDate == NULL) || (decode->afterDate == NULL) ||
|
||||
(decode->beforeDate[0] != cases[i].beforeTag) ||
|
||||
(decode->afterDate[0] != cases[i].afterTag) ||
|
||||
(cert_date_year(decode->beforeDate) != cases[i].beforeYear) ||
|
||||
(cert_date_year(decode->afterDate) != cases[i].afterYear)) {
|
||||
ret = WC_TEST_RET_ENC_NC;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = WC_TEST_RET_ENC_EC(ret);
|
||||
}
|
||||
FreeDecodedCert(decode);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
static wc_test_ret_t rsa_certgen_test(RsaKey* key, RsaKey* keypub, WC_RNG* rng, byte* tmp)
|
||||
{
|
||||
#if defined(WOLFSSL_SMALL_STACK) && !defined(WOLFSSL_NO_MALLOC)
|
||||
|
|
@ -30947,6 +31061,12 @@ static wc_test_ret_t rsa_certgen_test(RsaKey* key, RsaKey* keypub, WC_RNG* rng,
|
|||
FreeDecodedCert(decode);
|
||||
ERROR_OUT(WC_TEST_RET_ENC_EC(ret), exit_rsa);
|
||||
}
|
||||
/* Verify the generated validity dates use the RFC 5280 time format. */
|
||||
if ((cert_time_format_ok(decode->beforeDate) != 0) ||
|
||||
(cert_time_format_ok(decode->afterDate) != 0)) {
|
||||
FreeDecodedCert(decode);
|
||||
ERROR_OUT(WC_TEST_RET_ENC_NC, exit_rsa);
|
||||
}
|
||||
FreeDecodedCert(decode);
|
||||
#endif
|
||||
|
||||
|
|
@ -30956,6 +31076,13 @@ static wc_test_ret_t rsa_certgen_test(RsaKey* key, RsaKey* keypub, WC_RNG* rng,
|
|||
goto exit_rsa;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_TEST_CERT
|
||||
ret = cert_gen_time_boundary_test(myCert, der, key, rng, decode);
|
||||
if (ret != 0) {
|
||||
goto exit_rsa;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup Certificate */
|
||||
ret = wc_InitCert_ex(myCert, HEAP_HINT, devId);
|
||||
if (ret < 0) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue