Commit 009f395c4a for strongswan.org
commit 009f395c4a6af51adc20f7fb411f45a3954d1368
Author: raghu netrakar <raghu@security.bugqore.com>
Date: Fri Oct 2 15:31:56 2026 +0530
pgp: Fix out-of-bounds read when logging PGP creation times
A validity of more than 49710 days is now also handled correctly (did
overflow before).
Because `time_t` is signed, the creation time is now clamped the same
way the expiration time is on platforms where `time_t` is 32 bits.
Closes strongswan/strongswan#3160
Co-authored-by: Tobias Brunner <tobias@strongswan.org>
Fixes: bb7ae382fd9a ("added some debugging to pgp certificate parsing")
diff --git a/src/libstrongswan/plugins/pgp/pgp_cert.c b/src/libstrongswan/plugins/pgp/pgp_cert.c
index 5c35eedefd..901df398da 100644
--- a/src/libstrongswan/plugins/pgp/pgp_cert.c
+++ b/src/libstrongswan/plugins/pgp/pgp_cert.c
@@ -46,7 +46,7 @@ struct private_pgp_cert_t {
/**
* creation time
*/
- uint32_t created;
+ time_t created;
/**
* days the certificate is valid
@@ -74,6 +74,13 @@ struct private_pgp_cert_t {
refcount_t ref;
};
+/**
+ * Clamps the given time at Jan 19 03:14:07 UTC 2038 on 32-bit platforms
+ */
+#define CLAMP_TIME32(val) ({ \
+ typeof(val) _val = (val); \
+ (sizeof(time_t) == 4 && _val > TIME_32_BIT_SIGNED_MAX) ? \
+ TIME_32_BIT_SIGNED_MAX : _val; })
METHOD(certificate_t, get_type, certificate_type_t,
private_pgp_cert_t *this)
@@ -156,16 +163,16 @@ METHOD(certificate_t, get_validity, bool,
}
if (this->valid)
{
- expiry = this->created + this->valid * 24 * 60 * 60;
+ expiry = this->created + (uint64_t)this->valid * 24 * 60 * 60;
}
- if (!expiry || (sizeof(time_t) == 4 && expiry > TIME_32_BIT_SIGNED_MAX))
+ if (!expiry)
{
/* Jan 19 03:14:07 UTC 2038 */
until = TIME_32_BIT_SIGNED_MAX;
}
else
{
- until = expiry;
+ until = CLAMP_TIME32(expiry);
}
if (not_after)
{
@@ -271,6 +278,7 @@ private_pgp_cert_t *create_empty()
static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
{
chunk_t pubkey_packet = packet;
+ uint32_t created;
if (!pgp_read_scalar(&packet, 1, &this->version))
{
@@ -279,14 +287,14 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
switch (this->version)
{
case 3:
- if (!pgp_read_scalar(&packet, 4, &this->created) ||
+ if (!pgp_read_scalar(&packet, 4, &created) ||
!pgp_read_scalar(&packet, 2, &this->valid))
{
return FALSE;
}
break;
case 4:
- if (!pgp_read_scalar(&packet, 4, &this->created))
+ if (!pgp_read_scalar(&packet, 4, &created))
{
return FALSE;
}
@@ -296,6 +304,7 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
this->version);
return FALSE;
}
+ this->created = CLAMP_TIME32(created);
if (this->valid)
{
DBG2(DBG_ASN, "L2 - created %T, valid %d days", &this->created, FALSE,
@@ -356,6 +365,7 @@ static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
{
uint32_t version, len, type, created;
+ time_t created_time DBG_UNUSED;
if (!pgp_read_scalar(&packet, 1, &version))
{
@@ -387,8 +397,9 @@ static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
{
return FALSE;
}
+ created_time = CLAMP_TIME32(created);
DBG2(DBG_ASN, "L2 - v3 signature of type 0x%02x, created %T", type,
- &created, FALSE);
+ &created_time, FALSE);
}
/* TODO: parse and save signature to a list */
return TRUE;