summaryrefslogtreecommitdiff
path: root/nx_secure/src
diff options
context:
space:
mode:
Diffstat (limited to 'nx_secure/src')
-rw-r--r--nx_secure/src/nx_secure_generate_client_key_exchange.c46
-rw-r--r--nx_secure/src/nx_secure_generate_premaster_secret.c180
-rw-r--r--nx_secure/src/nx_secure_process_client_key_exchange.c55
-rw-r--r--nx_secure/src/nx_secure_process_server_key_exchange.c60
-rw-r--r--nx_secure/src/nx_secure_tls_process_certificate_verify.c73
-rw-r--r--nx_secure/src/nx_secure_tls_process_clienthello_extensions.c12
-rw-r--r--nx_secure/src/nx_secure_tls_send_certificate_verify.c21
-rw-r--r--nx_secure/src/nx_secure_tls_send_clienthello_extensions.c22
-rw-r--r--nx_secure/src/nx_secure_x509.c3
-rw-r--r--nx_secure/src/nx_secure_x509_expiration_check.c271
10 files changed, 676 insertions, 67 deletions
diff --git a/nx_secure/src/nx_secure_generate_client_key_exchange.c b/nx_secure/src/nx_secure_generate_client_key_exchange.c
index 0af26746..694694e4 100644
--- a/nx_secure/src/nx_secure_generate_client_key_exchange.c
+++ b/nx_secure/src/nx_secure_generate_client_key_exchange.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Some portions generated by Codex gpt-5.5.
+
/**************************************************************************/
/**************************************************************************/
@@ -124,15 +126,40 @@ NX_CRYPTO_EXTENDED_OUTPUT extended_output;
{
data_size = (UINT)(1 + tls_key_material -> nx_secure_tls_new_key_material_data[0]);
- if ((data_size > sizeof(tls_key_material -> nx_secure_tls_new_key_material_data)) ||
- (data_size > buffer_length))
+#ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
+ if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_PSK)
{
+ if ((tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size >
+ sizeof(tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id)) ||
+ (data_size > sizeof(tls_key_material -> nx_secure_tls_new_key_material_data)) ||
+ (((ULONG)data_size + 2u + tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size) > buffer_length))
+ {
- /* Packet buffer too small. */
- return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
+ /* Packet buffer too small. */
+ return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
+ }
+
+ data_buffer[0] = (UCHAR)((tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size & 0xFF00) >> 8);
+ data_buffer[1] = (UCHAR)(tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size & 0x00FF);
+ NX_SECURE_MEMCPY(&data_buffer[2], tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id,
+ tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size); /* Use case of memcpy is verified. */
+ NX_SECURE_MEMCPY(&data_buffer[2 + tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size],
+ tls_key_material -> nx_secure_tls_new_key_material_data, data_size); /* Use case of memcpy is verified. */
+ data_size += 2 + tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size;
}
+ else
+#endif /* NX_SECURE_ENABLE_PSK_CIPHERSUITES */
+ {
+ if ((data_size > sizeof(tls_key_material -> nx_secure_tls_new_key_material_data)) ||
+ (data_size > buffer_length))
+ {
- NX_SECURE_MEMCPY(data_buffer, tls_key_material -> nx_secure_tls_new_key_material_data, data_size); /* Use case of memcpy is verified. */
+ /* Packet buffer too small. */
+ return(NX_SECURE_TLS_PACKET_BUFFER_TOO_SMALL);
+ }
+
+ NX_SECURE_MEMCPY(data_buffer, tls_key_material -> nx_secure_tls_new_key_material_data, data_size); /* Use case of memcpy is verified. */
+ }
}
else
#endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE */
@@ -145,10 +172,10 @@ NX_CRYPTO_EXTENDED_OUTPUT extended_output;
/* Check for PSK ciphersuites. */
if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_PSK)
{
- if ((tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_hint_size >
- sizeof(tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_hint)) ||
- (tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_hint_size >
- (buffer_length - 2)))
+ if ((tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size >
+ sizeof(tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id)) ||
+ ((buffer_length < 2u) || (tls_credentials -> nx_secure_tls_client_psk.nx_secure_tls_psk_id_size >
+ (buffer_length - 2u))))
{
/* Packet buffer too small. */
@@ -327,4 +354,3 @@ NX_CRYPTO_EXTENDED_OUTPUT extended_output;
return(NX_SECURE_TLS_SUCCESS);
}
-
diff --git a/nx_secure/src/nx_secure_generate_premaster_secret.c b/nx_secure/src/nx_secure_generate_premaster_secret.c
index dea98428..63f35692 100644
--- a/nx_secure/src/nx_secure_generate_premaster_secret.c
+++ b/nx_secure/src/nx_secure_generate_premaster_secret.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Some portions generated by Codex gpt-5.5.
+
/**************************************************************************/
/**************************************************************************/
@@ -24,6 +26,141 @@
#include "nx_secure_tls.h"
+#ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _nx_secure_tls_psk_identity_lookup PORTABLE C */
+/* 6.x */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX Contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function searches the PSK store for an entry matching a peer */
+/* PSK identity. */
+/* */
+/* INPUT */
+/* */
+/* tls_credentials TLS credentials */
+/* psk_data Destination for PSK data */
+/* psk_length Destination for PSK length */
+/* psk_identity PSK identity data */
+/* identity_length PSK identity length */
+/* */
+/* OUTPUT */
+/* */
+/* status Completion status */
+/* */
+/* CALLS */
+/* */
+/* tx_mutex_get Get TLS protection */
+/* tx_mutex_put Release TLS protection */
+/* */
+/* CALLED BY */
+/* */
+/* _nx_secure_generate_premaster_secret Generate pre-master secret */
+/* */
+/**************************************************************************/
+static UINT _nx_secure_tls_psk_identity_lookup(NX_SECURE_TLS_CREDENTIALS *tls_credentials, UCHAR **psk_data, UINT *psk_length,
+ UCHAR *psk_identity, UINT identity_length)
+{
+UINT psk_list_size;
+UINT i;
+
+ /* Get the protection. */
+ tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
+
+ psk_list_size = tls_credentials -> nx_secure_tls_psk_count;
+
+ /* Loop through all PSKs, looking for a matching identity string. */
+ for (i = 0; i < psk_list_size; ++i)
+ {
+ if (identity_length == tls_credentials -> nx_secure_tls_psk_store[i].nx_secure_tls_psk_id_size)
+ {
+ if (NX_SECURE_MEMCMP(tls_credentials -> nx_secure_tls_psk_store[i].nx_secure_tls_psk_id,
+ psk_identity, identity_length) == 0)
+ {
+ *psk_data = tls_credentials -> nx_secure_tls_psk_store[i].nx_secure_tls_psk_data;
+ *psk_length = tls_credentials -> nx_secure_tls_psk_store[i].nx_secure_tls_psk_data_size;
+
+ /* Release the protection. */
+ tx_mutex_put(&_nx_secure_tls_protection);
+
+ return(NX_SUCCESS);
+ }
+ }
+ }
+
+ /* Release the protection. */
+ tx_mutex_put(&_nx_secure_tls_protection);
+
+ return(NX_SECURE_TLS_NO_MATCHING_PSK);
+}
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _nx_secure_tls_client_psk_save PORTABLE C */
+/* 6.x */
+/* AUTHOR */
+/* */
+/* Eclipse ThreadX Contributors */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function saves the PSK store entry selected by the server */
+/* identity hint so the client sends the matching identity in */
+/* ClientKeyExchange. */
+/* */
+/* INPUT */
+/* */
+/* tls_credentials TLS credentials */
+/* psk_store_index Selected PSK store index */
+/* */
+/* OUTPUT */
+/* */
+/* status Completion status */
+/* */
+/* CALLS */
+/* */
+/* tx_mutex_get Get TLS protection */
+/* tx_mutex_put Release TLS protection */
+/* */
+/* CALLED BY */
+/* */
+/* _nx_secure_generate_premaster_secret Generate pre-master secret */
+/* */
+/**************************************************************************/
+static UINT _nx_secure_tls_client_psk_save(NX_SECURE_TLS_CREDENTIALS *tls_credentials, UINT psk_store_index)
+{
+UINT status;
+
+ /* Get the protection. */
+ tx_mutex_get(&_nx_secure_tls_protection, TX_WAIT_FOREVER);
+
+ if (psk_store_index < tls_credentials -> nx_secure_tls_psk_count)
+ {
+ NX_SECURE_MEMCPY(&tls_credentials -> nx_secure_tls_client_psk,
+ &tls_credentials -> nx_secure_tls_psk_store[psk_store_index],
+ sizeof(NX_SECURE_TLS_PSK_STORE)); /* Use case of memcpy is verified. */
+ status = NX_SUCCESS;
+ }
+ else
+ {
+ status = NX_SECURE_TLS_NO_MATCHING_PSK;
+ }
+
+ /* Release the protection. */
+ tx_mutex_put(&_nx_secure_tls_protection);
+
+ return(status);
+}
+#endif
+
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
@@ -80,6 +217,7 @@ UINT status = NX_SECURE_TLS_SUCCESS;
UCHAR *psk_data;
UINT psk_length;
UINT index;
+UINT psk_store_index;
#endif
#if defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE) && !defined(NX_SECURE_DISABLE_X509)
NX_SECURE_X509_CERT *server_certificate;
@@ -125,9 +263,24 @@ UINT pre_master_secret_size;
containing the length of the PSK (in octets), and the PSK itself.
*/
- /* Client has to search for the PSK based on the identity hint. */
- status = _nx_secure_tls_psk_find(tls_credentials, &psk_data, &psk_length, tls_credentials -> nx_secure_tls_remote_psk_id,
- tls_credentials -> nx_secure_tls_remote_psk_id_size, NX_NULL);
+ if (session_type == NX_SECURE_TLS_SESSION_TYPE_SERVER)
+ {
+ /* Server searches for the PSK based on the identity requested by the client. */
+ status = _nx_secure_tls_psk_identity_lookup(tls_credentials, &psk_data, &psk_length,
+ tls_credentials -> nx_secure_tls_remote_psk_id,
+ tls_credentials -> nx_secure_tls_remote_psk_id_size);
+ }
+ else
+ {
+ /* Client has to search for the PSK based on the identity hint. */
+ status = _nx_secure_tls_psk_find(tls_credentials, &psk_data, &psk_length,
+ tls_credentials -> nx_secure_tls_remote_psk_id,
+ tls_credentials -> nx_secure_tls_remote_psk_id_size, &psk_store_index);
+ if (status == NX_SUCCESS)
+ {
+ status = _nx_secure_tls_client_psk_save(tls_credentials, psk_store_index);
+ }
+ }
if (status != NX_SUCCESS)
{
@@ -280,20 +433,32 @@ UINT pre_master_secret_size;
/* Now, using the identity as a key, find the PSK in our PSK store. */
if (session_type == NX_SECURE_TLS_SESSION_TYPE_SERVER)
{
- /* Server just uses its PSK. */
- psk_data = tls_credentials -> nx_secure_tls_psk_store[0].nx_secure_tls_psk_data;
- psk_length = tls_credentials -> nx_secure_tls_psk_store[0].nx_secure_tls_psk_data_size;
+ /* Server searches for the PSK based on the identity requested by the client. */
+ status = _nx_secure_tls_psk_identity_lookup(tls_credentials, &psk_data, &psk_length,
+ tls_credentials -> nx_secure_tls_remote_psk_id,
+ tls_credentials -> nx_secure_tls_remote_psk_id_size);
+
+ if (status != NX_SUCCESS)
+ {
+ return(status);
+ }
}
else
{
/* Client has to search for the PSK based on the identity hint. */
status = _nx_secure_tls_psk_find(tls_credentials, &psk_data, &psk_length, tls_credentials -> nx_secure_tls_remote_psk_id,
- tls_credentials -> nx_secure_tls_remote_psk_id_size, NX_NULL);
+ tls_credentials -> nx_secure_tls_remote_psk_id_size, &psk_store_index);
if (status != NX_SUCCESS)
{
return(status);
}
+
+ status = _nx_secure_tls_client_psk_save(tls_credentials, psk_store_index);
+ if (status != NX_SUCCESS)
+ {
+ return(status);
+ }
}
/* From RFC 4279:
@@ -369,4 +534,3 @@ UINT pre_master_secret_size;
return(status);
}
-
diff --git a/nx_secure/src/nx_secure_process_client_key_exchange.c b/nx_secure/src/nx_secure_process_client_key_exchange.c
index 97fd37d6..5e608abc 100644
--- a/nx_secure/src/nx_secure_process_client_key_exchange.c
+++ b/nx_secure/src/nx_secure_process_client_key_exchange.c
@@ -9,6 +9,8 @@
* SPDX-License-Identifier: MIT
**************************************************************************/
+// Some portions generated by Codex gpt-5.5.
+
/**************************************************************************/
/**************************************************************************/
@@ -93,6 +95,10 @@ UINT _nx_secure_process_client_key_exchange(const NX_SECURE_TLS_CIPHERSUITE_INFO
USHORT length;
#endif
UINT status = NX_SECURE_TLS_UNEXPECTED_MESSAGE;
+#ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
+UINT psk_identity_length;
+UINT generate_psk_secret;
+#endif
#if defined(NX_SECURE_ENABLE_ECJPAKE_CIPHERSUITE) || !defined(NX_SECURE_DISABLE_X509)
const NX_CRYPTO_METHOD *public_cipher_method;
#endif
@@ -176,8 +182,37 @@ UINT private_key_length;
#ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
/* Check for PSK ciphersuites and generate the pre-master-secret. */
+ generate_psk_secret = NX_FALSE;
if (ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_PSK)
{
+ if (message_length < 2)
+ {
+ return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
+ }
+
+ psk_identity_length = (UINT)((packet_buffer[0] << 8) | packet_buffer[1]);
+ if ((psk_identity_length > NX_SECURE_TLS_MAX_PSK_ID_SIZE) ||
+ ((psk_identity_length + 2u) > message_length))
+ {
+ return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
+ }
+
+ NX_SECURE_MEMCPY(tls_credentials -> nx_secure_tls_remote_psk_id, &packet_buffer[2], psk_identity_length); /* Use case of memcpy is verified. */
+ tls_credentials -> nx_secure_tls_remote_psk_id_size = psk_identity_length;
+ packet_buffer = &packet_buffer[2 + psk_identity_length];
+ message_length -= psk_identity_length + 2u;
+ generate_psk_secret = NX_TRUE;
+
+#if defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE) && !defined(NX_SECURE_DISABLE_X509)
+ if (ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDHE)
+ {
+ generate_psk_secret = NX_FALSE;
+ }
+#endif
+ }
+
+ if (generate_psk_secret == NX_TRUE)
+ {
status = _nx_secure_generate_premaster_secret(ciphersuite, protocol_version, tls_key_material, tls_credentials,
NX_SECURE_TLS_SESSION_TYPE_SERVER, received_remote_credentials,
public_cipher_metadata, public_cipher_metadata_size, tls_ecc_curves);
@@ -193,6 +228,11 @@ UINT private_key_length;
if (ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDH ||
ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDHE)
{
+ if (message_length < 1)
+ {
+ return(NX_SECURE_TLS_INCORRECT_MESSAGE_LENGTH);
+ }
+
length = packet_buffer[0];
if ((UINT)length + 1 > message_length)
@@ -334,6 +374,20 @@ UINT private_key_length;
return(status);
}
}
+
+#ifdef NX_SECURE_ENABLE_PSK_CIPHERSUITES
+ if ((ciphersuite -> nx_secure_tls_public_auth -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_PSK) &&
+ (ciphersuite -> nx_secure_tls_public_cipher -> nx_crypto_algorithm == NX_CRYPTO_KEY_EXCHANGE_ECDHE))
+ {
+ status = _nx_secure_generate_premaster_secret(ciphersuite, protocol_version, tls_key_material, tls_credentials,
+ NX_SECURE_TLS_SESSION_TYPE_SERVER, received_remote_credentials,
+ public_cipher_metadata, public_cipher_metadata_size, tls_ecc_curves);
+ if (status != NX_SUCCESS)
+ {
+ return(status);
+ }
+ }
+#endif
}
else
#endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE && !NX_SECURE_DISABLE_X509 */
@@ -579,4 +633,3 @@ UINT private_key_length;
return(status);
}
-
diff --git a/nx_secure/src/nx_secure_process_server_key_exchange.c b/nx_secure/src/nx_secure_process_server_key_exchange.c
index 32ace90c..e7b9f807 100644
--- a/nx_secure/src/nx_secure_process_server_key_exchange.c
+++ b/nx_secure/src/nx_secure_process_server_key_exchange.c
@@ -27,12 +27,14 @@
#ifdef NX_SECURE_ENABLE_DTLS
#include "nx_secure_dtls.h"
#endif /* NX_SECURE_ENABLE_DTLS */
+#include "nx_crypto_rsa.h"
#ifndef NX_SECURE_TLS_CLIENT_DISABLED
#if defined(NX_SECURE_ENABLE_ECC_CIPHERSUITE) && !defined(NX_SECURE_DISABLE_X509)
static UCHAR hash[64]; /* We concatenate MD5 and SHA-1 hashes into this buffer, OR SHA-256, SHA-384, SHA512. */
static UCHAR decrypted_signature[512];
+static UCHAR _nx_secure_ske_pss_scratch[600]; /* PSS verify scratch: db[<=511 B] + h_prime[<=64 B] for RSA-4096+SHA-512 */
#endif /* NX_SECURE_ENABLE_ECC_CIPHERSUITE && !NX_SECURE_DISABLE_X509 */
/**************************************************************************/
@@ -129,6 +131,7 @@ UCHAR *current_buffer;
UCHAR hash_algorithm;
UCHAR signature_algorithm;
USHORT signature_algorithm_id;
+UINT is_pss = NX_FALSE;
#if (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED)
UINT i;
#endif /* NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED */
@@ -330,6 +333,32 @@ UINT i;
hash_algorithm = current_buffer[0];
signature_algorithm = current_buffer[1];
current_buffer += 2;
+
+ /* Detect RSASSA-PSS signature schemes (RFC 8446 §4.2.3). The wire
+ tuple (0x08, 0x04/05/06) is not a valid TLS 1.2 (hash, sig) pair;
+ it encodes the 16-bit SignatureScheme code. Normalize it back to
+ (RSA, SHA-x) so the existing hash computation and RSA decrypt
+ path is reused; PSS-specific verify is selected via is_pss. */
+ switch (((UINT)hash_algorithm << 8) + (UINT)signature_algorithm)
+ {
+ case 0x0804u: /* rsa_pss_rsae_sha256 */
+ hash_algorithm = NX_SECURE_TLS_HASH_ALGORITHM_SHA256;
+ signature_algorithm = NX_SECURE_TLS_SIGNATURE_ALGORITHM_RSA;
+ is_pss = NX_TRUE;
+ break;
+ case 0x0805u: /* rsa_pss_rsae_sha384 */
+ hash_algorithm = NX_SECURE_TLS_HASH_ALGORITHM_SHA384;
+ signature_algorithm = NX_SECURE_TLS_SIGNATURE_ALGORITHM_RSA;
+ is_pss = NX_TRUE;
+ break;
+ case 0x0806u: /* rsa_pss_rsae_sha512 */
+ hash_algorithm = NX_SECURE_TLS_HASH_ALGORITHM_SHA512;
+ signature_algorithm = NX_SECURE_TLS_SIGNATURE_ALGORITHM_RSA;
+ is_pss = NX_TRUE;
+ break;
+ default:
+ break;
+ }
}
}
@@ -740,6 +769,36 @@ UINT i;
}
handler = NX_NULL;
+ if (is_pss)
+ {
+ /* RSASSA-PSS verification (RFC 8017 §9.1.2). The RSA "decrypt"
+ above gave us the encoded message EM; the hash to verify is
+ the SKE handshake hash already computed in hash[]. */
+ UINT hash_len = (UINT)(hash_method -> nx_crypto_ICV_size_in_bits >> 3);
+ UINT em_bits = ((UINT)signature_length << 3) - 1u; /* emBits = modBits - 1 */
+
+ status = _nx_crypto_rsa_pss_verify(
+ hash, hash_len,
+ decrypted_signature, em_bits,
+ hash_method,
+ tls_handshake_hash -> nx_secure_tls_handshake_hash_scratch,
+ tls_handshake_hash -> nx_secure_tls_handshake_hash_scratch_size,
+ _nx_secure_ske_pss_scratch, sizeof(_nx_secure_ske_pss_scratch));
+
+#ifdef NX_SECURE_KEY_CLEAR
+ NX_SECURE_MEMSET(hash, 0, sizeof(hash));
+ NX_SECURE_MEMSET(decrypted_signature, 0, sizeof(decrypted_signature));
+ NX_SECURE_MEMSET(_nx_secure_ske_pss_scratch, 0, sizeof(_nx_secure_ske_pss_scratch));
+#endif /* NX_SECURE_KEY_CLEAR */
+
+ if (status != NX_CRYPTO_SUCCESS)
+ {
+ return(NX_SECURE_TLS_SIGNATURE_VERIFICATION_ERROR);
+ }
+ }
+ else
+ {
+
#if (NX_SECURE_TLS_TLS_1_0_ENABLED || NX_SECURE_TLS_TLS_1_1_ENABLED)
#ifdef NX_SECURE_ENABLE_DTLS
if (protocol_version == NX_SECURE_TLS_VERSION_TLS_1_0 ||
@@ -810,6 +869,7 @@ UINT i;
{
return(NX_SECURE_TLS_SIGNATURE_VERIFICATION_ERROR);
}
+ } /* end of !is_pss PKCS#1 v1.5 path */
}
else if (signature_algorithm == NX_SECURE_TLS_SIGNATURE_ALGORITHM_ECDSA &&
auth_method -> nx_crypto_algorithm == NX_CRYPTO_DIGITAL_SIGNATURE_ECDSA)
diff --git a/nx_secure/src/nx_secure_tls_process_certificate_verify.c b/nx_secure/src/nx_secure_tls_process_certificate_verify.c
index 0d5bcd0d..e817767f 100644
--- a/nx_secure/src/nx_secure_tls_process_certificate_verify.c
+++ b/nx_secure/src/nx_secure_tls_process_certificate_verify.c
@@ -26,10 +26,14 @@
#ifdef NX_SECURE_ENABLE_DTLS
#include "nx_secure_dtls.h"
#endif /* NX_SECURE_ENABLE_DTLS */
+#include "nx_crypto_rsa.h"
#ifndef NX_SECURE_DISABLE_X509
-static UCHAR handshake_hash[64 + 34 + 32]; /* We concatenate MD5 and SHA-1 hashes into this buffer, OR SHA-256. */
+static UCHAR handshake_hash[64 + 34 + 64]; /* We concatenate MD5 and SHA-1 hashes into this buffer, OR SHA-256/384/512. */
static UCHAR _nx_secure_decrypted_signature[600];
+#if (NX_SECURE_TLS_TLS_1_3_ENABLED)
+static UCHAR _nx_secure_pss_scratch[600]; /* PSS verify: db[<=511 B] + h_prime[<=64 B] for RSA-4096+SHA-512 */
+#endif
#if (NX_SECURE_TLS_TLS_1_2_ENABLED)
static const UCHAR _NX_SECURE_OID_SHA256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
@@ -158,7 +162,7 @@ NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
#if (NX_SECURE_TLS_TLS_1_3_ENABLED)
if (tls_session -> nx_secure_tls_1_3)
{
- /* TLS1.3 uses RSASSA-PSS instead of RSASSA-PKCS. RSASSA-PSS is not supported now. */
+ /* Select crypto methods based on the wire signature algorithm code. */
switch ((UINT)((packet_buffer[0] << 8) + packet_buffer[1]))
{
case NX_SECURE_TLS_SIGNATURE_ECDSA_SHA256:
@@ -170,6 +174,15 @@ NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
case NX_SECURE_TLS_SIGNATURE_ECDSA_SHA512:
signature_algorithm = NX_SECURE_TLS_X509_TYPE_ECDSA_SHA_512;
break;
+ case 0x0804u: /* rsa_pss_rsae_sha256 */
+ signature_algorithm = NX_SECURE_TLS_X509_TYPE_RSA_SHA_256;
+ break;
+ case 0x0805u: /* rsa_pss_rsae_sha384 */
+ signature_algorithm = NX_SECURE_TLS_X509_TYPE_RSA_SHA_384;
+ break;
+ case 0x0806u: /* rsa_pss_rsae_sha512 */
+ signature_algorithm = NX_SECURE_TLS_X509_TYPE_RSA_SHA_512;
+ break;
default:
return(NX_SECURE_TLS_UNSUPPORTED_CERT_SIGN_ALG);
}
@@ -222,19 +235,22 @@ NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
NX_SECURE_MEMCPY(&handshake_hash[64], client_context, 34); /* Use case of memcpy is verified. */
}
- /* Copy in transcript hash. */
- NX_SECURE_MEMCPY(&handshake_hash[64 + 34], transcript_hash, 32); /* Use case of memcpy is verified. */
-
- handshake_hash_length = 130;
-
-
- /* Generate a hash of the data we just produced. */
- /* Use SHA-256 for now... */
+ /* Determine hash method and transcript hash length before copying.
+ hash_method drives the transcript hash size: 32 (SHA-256), 48 (SHA-384), 64 (SHA-512). */
hash_method = crypto_methods -> nx_secure_x509_hash_method;
metadata = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch;
metadata_size = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch_size;
+ {
+ UINT transcript_hash_len = (UINT)(hash_method -> nx_crypto_ICV_size_in_bits >> 3);
+
+ /* Copy in transcript hash — length depends on negotiated hash algorithm. */
+ NX_SECURE_MEMCPY(&handshake_hash[64 + 34], transcript_hash, transcript_hash_len); /* Use case of memcpy is verified. */
+
+ handshake_hash_length = 64u + 34u + transcript_hash_len;
+ }
+
/* Hash the data using the chosen hash method. */
if (hash_method -> nx_crypto_init)
@@ -497,11 +513,16 @@ NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
if (tls_session -> nx_secure_tls_protocol_version == NX_SECURE_TLS_VERSION_TLS_1_2)
#endif /* NX_SECURE_ENABLE_DTLS */
{
- /* Check the signature method. */
- if (packet_buffer[0] != NX_SECURE_TLS_HASH_ALGORITHM_SHA256 ||
- packet_buffer[1] != NX_SECURE_TLS_SIGNATURE_ALGORITHM_RSA)
+ /* Check the signature method (skipped for TLS 1.3: already validated above). */
+#if (NX_SECURE_TLS_TLS_1_3_ENABLED)
+ if (!tls_session -> nx_secure_tls_1_3)
+#endif
{
- return(NX_SECURE_TLS_UNKNOWN_CERT_SIG_ALGORITHM);
+ if (packet_buffer[0] != NX_SECURE_TLS_HASH_ALGORITHM_SHA256 ||
+ packet_buffer[1] != NX_SECURE_TLS_SIGNATURE_ALGORITHM_RSA)
+ {
+ return(NX_SECURE_TLS_UNKNOWN_CERT_SIG_ALGORITHM);
+ }
}
/* Get the length of the encrypted signature data. */
@@ -612,6 +633,30 @@ NX_SECURE_EC_PUBLIC_KEY *ec_pubkey;
}
}
+#if (NX_SECURE_TLS_TLS_1_3_ENABLED)
+ if (tls_session -> nx_secure_tls_1_3)
+ {
+ /* RSA-PSS verification for TLS 1.3 (RFC 8017 §9.1.2, RFC 8446 §4.4.3). */
+ UINT hash_len = (UINT)(hash_method -> nx_crypto_ICV_size_in_bits >> 3);
+ UINT em_bits = (data_size << 3) - 1u; /* emBits = modBits - 1 */
+
+ status = _nx_crypto_rsa_pss_verify(
+ handshake_hash, hash_len,
+ _nx_secure_decrypted_signature, em_bits,
+ hash_method,
+ tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch,
+ tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch_size,
+ _nx_secure_pss_scratch, sizeof(_nx_secure_pss_scratch));
+
+#ifdef NX_SECURE_KEY_CLEAR
+ NX_SECURE_MEMSET(handshake_hash, 0, sizeof(handshake_hash));
+ NX_SECURE_MEMSET(_nx_secure_decrypted_signature, 0, sizeof(_nx_secure_decrypted_signature));
+ NX_SECURE_MEMSET(_nx_secure_pss_scratch, 0, sizeof(_nx_secure_pss_scratch));
+#endif /* NX_SECURE_KEY_CLEAR */
+ return((status == NX_CRYPTO_SUCCESS) ? NX_SUCCESS : (UINT)NX_SECURE_TLS_CERTIFICATE_VERIFY_FAILURE);
+ }
+#endif /* NX_SECURE_TLS_TLS_1_3_ENABLED */
+
/* Check PKCS-1 Signature padding. The scheme is to start with the block type (0x00, 0x01 for signing)
then pad with 0xFF bytes (for signing) followed with a single 0 byte right before the payload,
which comes at the end of the RSA block. */
diff --git a/nx_secure/src/nx_secure_tls_process_clienthello_extensions.c b/nx_secure/src/nx_secure_tls_process_clienthello_extensions.c
index 34a551b2..ef5e70fa 100644
--- a/nx_secure/src/nx_secure_tls_process_clienthello_extensions.c
+++ b/nx_secure/src/nx_secure_tls_process_clienthello_extensions.c
@@ -1216,6 +1216,18 @@ VOID _nx_secure_tls_get_signature_algorithm_id(UINT signature_algorithm, USHORT
case NX_SECURE_TLS_SIGNATURE_ECDSA_SHA512:
*signature_algorithm_id = NX_SECURE_TLS_X509_TYPE_ECDSA_SHA_512;
break;
+ /* RSASSA-PSS schemes (RFC 8446 §4.2.3). Mapped to the same internal IDs
+ as PKCS#1 v1.5 so the certificate cipher table lookup finds the (RSA,
+ SHA-x) pair. PSS-vs-PKCS1 dispatch is done at signature-verify time. */
+ case 0x0804u: /* rsa_pss_rsae_sha256 */
+ *signature_algorithm_id = NX_SECURE_TLS_X509_TYPE_RSA_SHA_256;
+ break;
+ case 0x0805u: /* rsa_pss_rsae_sha384 */
+ *signature_algorithm_id = NX_SECURE_TLS_X509_TYPE_RSA_SHA_384;
+ break;
+ case 0x0806u: /* rsa_pss_rsae_sha512 */
+ *signature_algorithm_id = NX_SECURE_TLS_X509_TYPE_RSA_SHA_512;
+ break;
default:
return;
}
diff --git a/nx_secure/src/nx_secure_tls_send_certificate_verify.c b/nx_secure/src/nx_secure_tls_send_certificate_verify.c
index c022250a..35c10355 100644
--- a/nx_secure/src/nx_secure_tls_send_certificate_verify.c
+++ b/nx_secure/src/nx_secure_tls_send_certificate_verify.c
@@ -28,7 +28,7 @@
#endif /* NX_SECURE_ENABLE_DTLS */
#ifndef NX_SECURE_DISABLE_X509
-static UCHAR handshake_hash[64 + 34 + 32]; /* We concatenate MD5 and SHA-1 hashes into this buffer, OR SHA-256. */
+static UCHAR handshake_hash[64 + 34 + 64]; /* We concatenate MD5 and SHA-1 hashes into this buffer, OR SHA-256/384/512. */
static UCHAR _nx_secure_padded_signature[600];
#if (NX_SECURE_TLS_TLS_1_2_ENABLED)
@@ -241,19 +241,22 @@ NX_CRYPTO_EXTENDED_OUTPUT extended_output;
NX_SECURE_MEMCPY(&handshake_hash[64], server_context, 34); /* Use case of memcpy is verified. */
}
- /* Copy in transcript hash. */
- NX_SECURE_MEMCPY(&handshake_hash[64 + 34], transcript_hash, 32); /* Use case of memcpy is verified. */
-
- handshake_hash_length = 130;
-
-
- /* Generate a hash of the data we just produced. */
- /* Use SHA-256 for now... */
+ /* Determine hash method and transcript hash length before copying.
+ hash_method drives the transcript hash size: 32 (SHA-256), 48 (SHA-384), 64 (SHA-512). */
hash_method = crypto_methods -> nx_secure_x509_hash_method;
metadata = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch;
metadata_size = tls_session -> nx_secure_tls_handshake_hash.nx_secure_tls_handshake_hash_scratch_size;
+ {
+ UINT transcript_hash_len = (UINT)(hash_method -> nx_crypto_ICV_size_in_bits >> 3);
+
+ /* Copy in transcript hash — length depends on negotiated hash algorithm. */
+ NX_SECURE_MEMCPY(&handshake_hash[64 + 34], transcript_hash, transcript_hash_len); /* Use case of memcpy is verified. */
+
+ handshake_hash_length = 64u + 34u + transcript_hash_len;
+ }
+
if (hash_method -> nx_crypto_init)
{
diff --git a/nx_secure/src/nx_secure_tls_send_clienthello_extensions.c b/nx_secure/src/nx_secure_tls_send_clienthello_extensions.c
index 0c9ce53b..08364122 100644
--- a/nx_secure/src/nx_secure_tls_send_clienthello_extensions.c
+++ b/nx_secure/src/nx_secure_tls_send_clienthello_extensions.c
@@ -451,6 +451,28 @@ UCHAR sig_algo = 0;
}
}
+ /* TLS 1.3 requires RSA-PSS instead of PKCS#1 v1.5 (RFC 8446 §4.2.3).
+ Map RSA + SHA-256/384/512 to rsa_pss_rsae_sha256/384/512 (0x0804/0805/0806). */
+ if (tls_session -> nx_secure_tls_1_3 &&
+ sig_algo == NX_SECURE_TLS_SIGNATURE_ALGORITHM_RSA)
+ {
+ switch (hash_algo)
+ {
+ case NX_SECURE_TLS_HASH_ALGORITHM_SHA256:
+ *signature_algorithm = 0x0804u; /* rsa_pss_rsae_sha256 */
+ break;
+ case NX_SECURE_TLS_HASH_ALGORITHM_SHA384:
+ *signature_algorithm = 0x0805u; /* rsa_pss_rsae_sha384 */
+ break;
+ case NX_SECURE_TLS_HASH_ALGORITHM_SHA512:
+ *signature_algorithm = 0x0806u; /* rsa_pss_rsae_sha512 */
+ break;
+ default:
+ *signature_algorithm = 0;
+ }
+ return;
+ }
+
/* In TLS 1.3, the signing curve is constrained. */
if (tls_session -> nx_secure_tls_1_3 &&
(named_curve != 0) &&
diff --git a/nx_secure/src/nx_secure_x509.c b/nx_secure/src/nx_secure_x509.c
index ef446aff..483d2c3e 100644
--- a/nx_secure/src/nx_secure_x509.c
+++ b/nx_secure/src/nx_secure_x509.c
@@ -1054,7 +1054,7 @@ const UCHAR *current_buffer;
return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
}
- cert -> nx_secure_x509_validity_format = tlv_type;
+ cert -> nx_secure_x509_not_before_validity_format = tlv_type;
cert -> nx_secure_x509_not_before = tlv_data;
cert -> nx_secure_x509_not_before_length = (USHORT)tlv_length;
@@ -1075,6 +1075,7 @@ const UCHAR *current_buffer;
return(NX_SECURE_X509_UNEXPECTED_ASN1_TAG);
}
+ cert -> nx_secure_x509_not_after_validity_format = tlv_type;
cert -> nx_secure_x509_not_after = tlv_data;
cert -> nx_secure_x509_not_after_length = (USHORT)tlv_length;
diff --git a/nx_secure/src/nx_secure_x509_expiration_check.c b/nx_secure/src/nx_secure_x509_expiration_check.c
index e0e46751..d0fc0b00 100644
--- a/nx_secure/src/nx_secure_x509_expiration_check.c
+++ b/nx_secure/src/nx_secure_x509_expiration_check.c
@@ -28,6 +28,8 @@
static UINT _nx_secure_x509_asn1_time_to_unix_convert(const UCHAR *asn1_time, USHORT asn1_length,
USHORT format, ULONG *unix_time);
+static ULONG _nx_secure_count_leap_years(ULONG start_year, ULONG end_year);
+
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
@@ -71,7 +73,7 @@ UINT status;
/* First, convert the X.509 ASN.1 time format into 32-bit UINX-epoch format of the "not before" field. */
status = _nx_secure_x509_asn1_time_to_unix_convert(certificate -> nx_secure_x509_not_before, certificate -> nx_secure_x509_not_before_length,
- certificate -> nx_secure_x509_validity_format, &not_before);
+ certificate -> nx_secure_x509_not_before_validity_format, &not_before);
if (status != NX_SECURE_X509_SUCCESS)
{
return(status);
@@ -79,7 +81,7 @@ UINT status;
/* Convert the "not after" time field. */
status = _nx_secure_x509_asn1_time_to_unix_convert(certificate -> nx_secure_x509_not_after, certificate -> nx_secure_x509_not_after_length,
- certificate -> nx_secure_x509_validity_format, &not_after);
+ certificate -> nx_secure_x509_not_after_validity_format, &not_after);
if (status != NX_SECURE_X509_SUCCESS)
{
return(status);
@@ -107,18 +109,27 @@ UINT status;
/* Helper function to convert the ASN.1 time formats into UNIX epoch time for comparison. */
#define date_2_chars_to_int(buffer, index) (ULONG)(((buffer[index] - '0') * 10) + (buffer[index + 1] - '0'))
+#define date_4_chars_to_int(buffer, index) (ULONG)(((buffer[index] - '0') * 1000) + ((buffer[index + 1] - '0') * 100) + ((buffer[index + 2] - '0') * 10) + (buffer[index + 3] - '0'))
+#define date_char_is_digit(character) (((character) >= '0') && ((character) <= '9'))
+
+/* Helper function to determine if a given year is a leap year */
+
+#define is_leap_year(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
/* Array indexed on month - 1 gives the total number of days in all previous months (through last day of previous
month). Leap years are handled in the logic below and are not reflected in this array. */
/* J F M A M J J A S O N D */
static const UINT days_before_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+/* Define epoch year for UNIX time */
+static const ULONG unix_epoch = 1970;
+
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _nx_secure_x509_asn1_time_to_unix_convert PORTABLE C */
-/* 6.1.11 */
+/* 6.1.12 */
/* AUTHOR */
/* */
/* Timothy Stapko, Microsoft Corporation */
@@ -141,7 +152,7 @@ static const UINT days_before_month[12] = {0, 31, 59, 90, 120, 151, 181, 212, 24
/* */
/* CALLS */
/* */
-/* None */
+/* _nx_secure_count_leap_years */
/* */
/* CALLED BY */
/* */
@@ -154,16 +165,28 @@ static UINT _nx_secure_x509_asn1_time_to_unix_convert(const UCHAR *asn1_time, US
ULONG year, month, day, hour, minute, second;
UINT index;
- NX_CRYPTO_PARAMETER_NOT_USED(asn1_length);
index = 0;
/* See what format we are using. */
if (format == NX_SECURE_ASN_TAG_UTC_TIME)
{
/* UTCTime is either "YYMMDDhhmm[ss]Z" or "YYMMDDhhmm[ss](+|-)hhmm" */
+ if (asn1_length < 11)
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ for (index = 0; index < 10; index++)
+ {
+ if (!date_char_is_digit(asn1_time[index]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+ }
+
year = date_2_chars_to_int(asn1_time, 0);
month = date_2_chars_to_int(asn1_time, 2);
- day = date_2_chars_to_int(asn1_time, 4) - 1; /* For calculations, day is 0-based. */
+ day = date_2_chars_to_int(asn1_time, 4);
hour = date_2_chars_to_int(asn1_time, 6);
minute = date_2_chars_to_int(asn1_time, 8);
second = 0;
@@ -174,10 +197,26 @@ UINT index;
/* Check for optional seconds. */
if (asn1_time[index] != 'Z' && asn1_time[index] != '+' && asn1_time[index] != '-')
{
+ if (((ULONG)index + 1) >= asn1_length ||
+ !date_char_is_digit(asn1_time[index]) ||
+ !date_char_is_digit(asn1_time[index + 1]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
second = date_2_chars_to_int(asn1_time, index);
index += 2;
}
+ if ((month < 1) || (month > 12) || (day < 1) || (day > 31) ||
+ (hour > 23) || (minute > 59) || (second > 59) || (index >= asn1_length))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ /* For calculations, day is 0-based. */
+ day -= 1;
+
/* Check for GMT time or local time offset. */
if (asn1_time[index] != 'Z')
{
@@ -185,6 +224,15 @@ UINT index;
* result in values > 24 or < 0 but that is OK for the calculations. */
if (asn1_time[index] == '+')
{
+ if (((ULONG)index + 4) >= asn1_length ||
+ !date_char_is_digit(asn1_time[index + 1]) ||
+ !date_char_is_digit(asn1_time[index + 2]) ||
+ !date_char_is_digit(asn1_time[index + 3]) ||
+ !date_char_is_digit(asn1_time[index + 4]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
index++; /* Skip the '+' */
hour -= date_2_chars_to_int(asn1_time, index);
index += 2;
@@ -192,6 +240,15 @@ UINT index;
}
else if (asn1_time[index] == '-')
{
+ if (((ULONG)index + 4) >= asn1_length ||
+ !date_char_is_digit(asn1_time[index + 1]) ||
+ !date_char_is_digit(asn1_time[index + 2]) ||
+ !date_char_is_digit(asn1_time[index + 3]) ||
+ !date_char_is_digit(asn1_time[index + 4]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
index++; /* Skip the '-' */
hour += date_2_chars_to_int(asn1_time, index);
index += 2;
@@ -206,31 +263,28 @@ UINT index;
/* printf("year: %lu, month: %lu, day: %lu, hour: %lu, minute: %lu, second: %lu\n", year, month, day, hour, minute, second);*/
- /* Now we have our time in integers, calculate leap years. We aren't concerned with years outside the UNIX
- time range of 1970-2038 so we can assume every 4 years starting with 1972 is a leap year (years divisible
- by 100 are NOT leap years unless also divisible by 400, which the year 2000 is). Using integer division gives
- us the floor of the number of 4 year periods, so add 1. */
+ /* Now we have our time in integers, calculate leap years that have occurred. */
if (year >= 70)
{
- /* Year is before 2000. Subtract 72 to get duration from first leap year in epoch. */
- year -= 70;
- day += ((year + 2) / 4);
+ /* Year is before 2000. Add 1900 to get actual year. */
+ year += 1900;
}
else
{
- /* Year is 2000 or greater. Add 28 (2000-1972) to get duration from first leap year in epoch. */
- year += 30;
- day += ((year - 2) / 4) + 1;
+ /* Year is 2000 or greater. Add 2000 to get actual year. */
+ year += 2000;
}
+ day += _nx_secure_count_leap_years(unix_epoch, year);
+
/* If it is leap year and month is before March, subtract 1 day. */
- if (((year + 2) % 4 == 0) && (month < 3))
+ if ((is_leap_year(year)) && (month < 3))
{
day -= 1;
}
/* Finally, calculate the number of seconds from the extracted values. */
- day += year * 365;
+ day += (year - unix_epoch) * 365;
day += days_before_month[month - 1];
hour += day * 24;
minute += hour * 60;
@@ -241,12 +295,133 @@ UINT index;
}
else if (format == NX_SECURE_ASN_TAG_GENERALIZED_TIME)
{
- /* Generalized time formats:
- Local time only. ``YYYYMMDDHH[MM[SS[.fff]]]'', where the optional fff is three decimal places (fractions of seconds).
- Universal time (UTC time) only. ``YYYYMMDDHH[MM[SS[.fff]]]Z''. MM, SS, .fff are optional.
- Difference between local and UTC times. ``YYYYMMDDHH[MM[SS[.fff]]]+-HHMM''. +/-HHMM is local time offset. */
- /* TODO: Implement conversion to 32-bit UNIX time. */
- return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ /* GeneralizedTime is parsed as YYYYMMDDHHMM[SS[.fff]](Z|+HHMM|-HHMM). */
+ if (asn1_length < 13)
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ for (index = 0; index < 12; index++)
+ {
+ if (!date_char_is_digit(asn1_time[index]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+ }
+
+ year = date_4_chars_to_int(asn1_time, 0);
+ month = date_2_chars_to_int(asn1_time, 4);
+ day = date_2_chars_to_int(asn1_time, 6);
+ hour = date_2_chars_to_int(asn1_time, 8);
+ minute = date_2_chars_to_int(asn1_time, 10);
+ second = 0;
+ index = 12;
+
+ /* Check for optional seconds. */
+ if (asn1_time[index] != 'Z' && asn1_time[index] != '+' && asn1_time[index] != '-')
+ {
+ if (((ULONG)index + 1) >= asn1_length ||
+ !date_char_is_digit(asn1_time[index]) ||
+ !date_char_is_digit(asn1_time[index + 1]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ second = date_2_chars_to_int(asn1_time, index);
+ index += 2;
+
+ /* Skip optional fractional seconds. */
+ if ((index < asn1_length) && (asn1_time[index] == '.'))
+ {
+ index++;
+ if ((index >= asn1_length) || !date_char_is_digit(asn1_time[index]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ while ((index < asn1_length) && date_char_is_digit(asn1_time[index]))
+ {
+ index++;
+ }
+ }
+ }
+
+ if ((year < unix_epoch) || (month < 1) || (month > 12) || (day < 1) || (day > 31) ||
+ (hour > 23) || (minute > 59) || (second > 59) || (index >= asn1_length))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ /* For calculations, day is 0-based. */
+ day -= 1;
+
+ /* Check for GMT time or local time offset. */
+ if (asn1_time[index] == 'Z')
+ {
+ index++;
+ }
+ else if (asn1_time[index] == '+')
+ {
+ if (((ULONG)index + 4) >= asn1_length ||
+ !date_char_is_digit(asn1_time[index + 1]) ||
+ !date_char_is_digit(asn1_time[index + 2]) ||
+ !date_char_is_digit(asn1_time[index + 3]) ||
+ !date_char_is_digit(asn1_time[index + 4]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ index++; /* Skip the '+' */
+ hour -= date_2_chars_to_int(asn1_time, index);
+ index += 2;
+ minute -= date_2_chars_to_int(asn1_time, index);
+ index += 2;
+ }
+ else if (asn1_time[index] == '-')
+ {
+ if (((ULONG)index + 4) >= asn1_length ||
+ !date_char_is_digit(asn1_time[index + 1]) ||
+ !date_char_is_digit(asn1_time[index + 2]) ||
+ !date_char_is_digit(asn1_time[index + 3]) ||
+ !date_char_is_digit(asn1_time[index + 4]))
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ index++; /* Skip the '-' */
+ hour += date_2_chars_to_int(asn1_time, index);
+ index += 2;
+ minute += date_2_chars_to_int(asn1_time, index);
+ index += 2;
+ }
+ else
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ if (index != asn1_length)
+ {
+ return(NX_SECURE_X509_INVALID_DATE_FORMAT);
+ }
+
+ /* Now we have our time in integers, calculate leap years that have occurred. */
+ day += _nx_secure_count_leap_years(unix_epoch, year);
+
+ /* If it is leap year and month is before March, subtract 1 day. */
+ if (is_leap_year(year) && (month < 3))
+ {
+ day -= 1;
+ }
+
+ /* Finally, calculate the number of seconds from the extracted values. */
+ day += (year - unix_epoch) * 365;
+ day += days_before_month[month - 1];
+ hour += day * 24;
+ minute += hour * 60;
+ second += minute * 60;
+
+ /* Finally, return the converted time. */
+ *unix_time = second;
}
else
{
@@ -256,3 +431,51 @@ UINT index;
return(NX_SECURE_X509_SUCCESS);
}
+
+/**************************************************************************/
+/* */
+/* FUNCTION RELEASE */
+/* */
+/* _nx_secure_count_leap_years PORTABLE C */
+/* 6.4.1 */
+/* AUTHOR */
+/* */
+/* Simon Scurrell, T3S Solutions Ltd */
+/* */
+/* DESCRIPTION */
+/* */
+/* This function calculates the number of leap years that have */
+/* occurred between the given start and end years. */
+/* */
+/* INPUT */
+/* */
+/* start_year 4-digit start year (YYYY) */
+/* end_year 4-digit end year (YYYY) */
+/* */
+/* OUTPUT */
+/* */
+/* count Returns the number of leap years */
+/* */
+/* CALLS */
+/* */
+/* None */
+/* */
+/* CALLED BY */
+/* */
+/* _nx_secure_x509_asn1_time_to_unix_convert ASN.1 time convert */
+/* */
+/**************************************************************************/
+static ULONG _nx_secure_count_leap_years(ULONG start_year, ULONG end_year)
+{
+ ULONG count = 0;
+
+ for (ULONG year = start_year; year <= end_year; year++)
+ {
+ if (is_leap_year(year))
+ {
+ count += 1;
+ }
+ }
+
+ return count;
+}