validate cert and private key

Discussion to talk about software related topics only.
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

validate cert and private key

Post by RebootExpert »

Using 2.9.3 and mod5441x. I upload the cert and key files and extract the data from them, and I use IsSSL_CertNKeyValid() to do validation.
However if I upload the cert and key file that don't match, the function still return true. This is strange.
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

and the function SSL_IsCertExpired always return false even though the certificate is expired
User avatar
Jon
Posts: 79
Joined: Mon Feb 05, 2018 10:54 am

Re: validate cert and private key

Post by Jon »

Hi RebootExpert,

The function IsSSL_CertNKeyValid() only checks to make sure that the certificate and key in memory isn't corrupted and that they can actually be used in the system. It doesn't validate them against each other. Our documentation should be updated to reflect that, and I appreciate you pointing it out. Sorry for the confusion there.

For SSL_IsCertExpired(), there are a couple of reasons that the function might return false. The first is if it's unable to get an accurate system time. In 2.9.3 (we just changed this for our upcoming release), the function first tries to set the time from an NTP pool. If it's unable to successfully do that, it will just return false.

It will also return false if it can't successfully get the expiration date from the certificate. In our upcoming release, we've changed this function to return error codes that give better information.

If you want to forgo the NTP time server status check (if you set it previously in your code, or are setting the time manually), you can use the modified function below:

bool SSL_IsCertExpiredMod( unsigned char* certBuff, int certLen, uint16_t certBuffFormat /*= SSL_FILETYPE_PEM*/ )
{
uint16_t expBufLen = 64;
unsigned char expBuf[expBufLen] = {0};
if(SSL_GetExpirationDate(certBuff, certLen, expBuf, expBufLen, certBuffFormat))
{
// Get current time and compare it to expiration date
time_t now = time(nullptr);
//NBString dateInfo((const char*)expBuf);

struct tm ExpTime;
char tempBuf[4] = {0};
//ExpTime.tm_mon = dateInfo.substr(6, 2).stoi();
sniprintf(tempBuf, 3, "%s", &expBuf[6]);
ExpTime.tm_mon = atoi(tempBuf);
//ExpTime.tm_mday = dateInfo.substr(8, 2).stoi();
sniprintf(tempBuf, 3, "%s", &expBuf[8]);
ExpTime.tm_mday = atoi(tempBuf);
//ExpTime.tm_year = dateInfo.substr(2, 4).stoi() - 1900;
sniprintf(tempBuf, 5, "%s", &expBuf[2]);
ExpTime.tm_year = atoi(tempBuf);

//ExpTime.tm_hour = dateInfo.substr(10, 2).stoi();
sniprintf(tempBuf, 3, "%s", &expBuf[10]);
ExpTime.tm_hour = atoi(tempBuf);
//ExpTime.tm_min = dateInfo.substr(12, 2).stoi();
sniprintf(tempBuf, 3, "%s", &expBuf[12]);
ExpTime.tm_min = atoi(tempBuf);
//ExpTime.tm_sec = dateInfo.substr(14, 2).stoi();
sniprintf(tempBuf, 3, "%s", &expBuf[14]);
ExpTime.tm_sec = atoi(tempBuf);

/* set_time() need a parameter of time_t, so use mktime() to convert
* a struct tm type to a time_t type.
*/
time_t exp = mktime(&ExpTime);
return (difftime(exp, now) < 0);
}

return false;
}

You'll note that we still need to return false at the bottom of the function. You can also modify the original SSL_GetExpirationDate() if you like. It's found in the nburn\system\cryptolib\NetBurner\NbWolfSsl.cpp

Please let me know if we can help with any other questions.

Kind Regards,
Jon
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

That make sense. Thanks for the clarification.
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

Try using your code, I print out expBuf that store the expiration date of my cert:

expBuf = 210320233312Z
expBuf = 23 13 50 49 48 51 50 48 50 51 51 51 49 50 90 (correspond acsii value)

why the first two char are 23(ETB), 13(CR) instead of 50('2') and 48('0') (assume it's 2021) and end in 90('Z') ?
and it causes the indices later in the code are off which result a false return.
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

So I update your code a little, now it's working ok. But again should the year in format of yyyy instead yy ? And the ending 'Z' char ?

Code: Select all

bool SSL_IsCertExpiredMod( unsigned char* certBuff, int certLen, uint16_t certBuffFormat = SSL_FILETYPE_PEM )
{
	uint16_t expBufLen = 64;
	unsigned char expBuf[expBufLen] = {0};
	if(SSL_GetExpirationDate(certBuff, certLen, expBuf, expBufLen, certBuffFormat))
	{
		//expBuf = {yyMMddhhmmss} eg 210320165216 is 3/20/2021 4:52:16PM. somehow the first char start at index 2.
		//printf("%s\n", expBuf);

		//Get current time and compare it to expiration date
		time_t now = time(nullptr);

		struct tm ExpTime;
		char tempBuf[3] = {0,0,'\0'};
		sniprintf(tempBuf, 2, "%s", &expBuf[2]);
		ExpTime.tm_year = atoi(tempBuf) + 2000 - 1900; 					// years since 1900

		sniprintf(tempBuf, 2, "%s", &expBuf[4]);
		ExpTime.tm_mon = atoi(tempBuf) - 1; 						// month range 0-11

		sniprintf(tempBuf, 2, "%s", &expBuf[6]);
		ExpTime.tm_mday = atoi(tempBuf);   						// day range 1-31

		sniprintf(tempBuf, 2, "%s", &expBuf[8]);
		ExpTime.tm_hour = atoi(tempBuf);						// hour range 0-23

		sniprintf(tempBuf, 2, "%s", &expBuf[10]);
		ExpTime.tm_min = atoi(tempBuf);							// minute range 0-59

		sniprintf(tempBuf, 2, "%s", &expBuf[12]);
		ExpTime.tm_sec = atoi(tempBuf);							// sec range 0-60

		/* set_time() need a parameter of time_t, so use mktime() to convert
		* a struct tm type to a time_t type.
		*/
		time_t exp = mktime(&ExpTime);
		//printf("now = %lld\nexpired time = %lld\n", now, exp);
		return (difftime(exp, now) < 0);
	}

	return false;
}
User avatar
Jon
Posts: 79
Joined: Mon Feb 05, 2018 10:54 am

Re: validate cert and private key

Post by Jon »

Hi Reboot Expert,

The 'Z' character indicates Zulu time, and is part of the standard time format. Looking more into this, though, the format for the expiration date will be dependent on how long the certificate is valid for. For certificates that are valid through 2049, the format should be UTCTime and is YYMMDDHHMMSSZ. For certificates that are valid from 2050 on, the format should be YYYYMMDDHHMMSSZ. This is better documented in RFC 5280, sections 4.1.2.5.

That said, our self generated certs always seem to print out in the second format, even with a validity of 10 years from the date of generation. For example, when I ran it just now, I got a value of 20310322194821Z when I printed the buffer. The way the function currently works, it expects the dates to be in this format and doesn't properly handle the 12 digit date code. Additional, I realized that we are not properly null terminating the strings that are read from sniprintf(). I've updated the function here:

bool SSL_IsCertExpired( unsigned char* certBuff, int certLen, uint16_t certBuffFormat /*= SSL_FILETYPE_PEM*/ )
{
// Make sure we have system time
if(!SetTimeNTPFromPool(false))
{
return false;
}

uint16_t expBufLen = 64;
unsigned char expBuf[expBufLen] = {0};
if(SSL_GetExpirationDate(certBuff, certLen, expBuf, expBufLen, certBuffFormat))
{
// Get current time and compare it to expiration date
time_t now = time(nullptr);
//NBString dateInfo((const char*)expBuf);

iprintf("Expiration information: ");
for(int i = 0; i < expBufLen; i++)
{
iprintf("%c", expBuf);
}
iprintf("\r\n");

struct tm ExpTime;
char tempBuf[4] = {0};
sniprintf(tempBuf, 3, "%s", &expBuf[6]);
tempBuf[2] = '\0';
ExpTime.tm_mon = atoi(tempBuf);
iprintf("Month: %d\r\n", ExpTime.tm_mon);

sniprintf(tempBuf, 3, "%s", &expBuf[8]);
tempBuf[2] = '\0';
ExpTime.tm_mday = atoi(tempBuf);
iprintf("Day: %d\r\n", ExpTime.tm_mday);

sniprintf(tempBuf, 5, "%s", &expBuf[2]);
tempBuf[4] = '\0';
ExpTime.tm_year = atoi(tempBuf);
iprintf("Year: %d\r\n", ExpTime.tm_year);

sniprintf(tempBuf, 3, "%s", &expBuf[10]);
tempBuf[2] = '\0';
ExpTime.tm_hour = atoi(tempBuf);
iprintf("Hour: %d\r\n", ExpTime.tm_hour);

sniprintf(tempBuf, 3, "%s", &expBuf[12]);
tempBuf[2] = '\0';
ExpTime.tm_min = atoi(tempBuf);
iprintf("Min: %d\r\n", ExpTime.tm_min);

sniprintf(tempBuf, 3, "%s", &expBuf[14]);
tempBuf[2] = '\0';
ExpTime.tm_sec = atoi(tempBuf);
iprintf("Sec: %d\r\n", ExpTime.tm_sec);

/* set_time() need a parameter of time_t, so use mktime() to convert
* a struct tm type to a time_t type.
*/
time_t exp = mktime(&ExpTime);
return (difftime(exp, now) < 0);
}
return false;
}

I've also added some print statements to verify that they're setting the right expiration date. When I added this function call to the SslOnBoardCertGeneration example, it yielded the following output:

Expiration information: <two bad odd characters>20310322195648Z
Month: 3
Day: 22
Year: 2031
Hour: 19
Min: 56
Sec: 48

Would you mind testing this function against your cert and seeing what the output is when you call it? Also, do you happen to know the expiration date of your certificate offhand? From the previous message it sounds like it should already be expired, but I wanted to double check.

Kind Regards,
Jon
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

Thanks for the thorough explanation.
The reason I use SSL_IsCertExpired() is that my webpage has a feature allow user to upload their cert and key, and I will check the expired date of the cert and then check if the cert and key were match which is why I ask about the function IsSSL_CertNKeyValid in the first place.
So I generated an expired cert by using openssl to test out the SSL_IsCertExpired(), and it always return false, in fact it should be true in this case.

and here's the output I use your function:
test.png
test.png (4.74 KiB) Viewed 3966 times
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

I think the problem is about SSL_GetExpirationDate() since it did the job to get the expiration date of a cert.
RebootExpert
Posts: 78
Joined: Fri Oct 09, 2020 2:57 pm

Re: validate cert and private key

Post by RebootExpert »

Or is the function specific for the self generated cert use only?
Post Reply