summaryrefslogtreecommitdiff
path: root/src/libstrongswan/asn1/asn1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/asn1/asn1.c')
-rw-r--r--src/libstrongswan/asn1/asn1.c80
1 files changed, 57 insertions, 23 deletions
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c
index d860ad9a2..38a6ad688 100644
--- a/src/libstrongswan/asn1/asn1.c
+++ b/src/libstrongswan/asn1/asn1.c
@@ -88,7 +88,7 @@ int asn1_known_oid(chunk_t object)
}
}
}
- return -1;
+ return OID_UNKNOWN;
}
/*
@@ -129,7 +129,8 @@ chunk_t asn1_build_known_oid(int n)
chunk_t asn1_oid_from_string(char *str)
{
enumerator_t *enumerator;
- u_char buf[64];
+ size_t buf_len = 64;
+ u_char buf[buf_len];
char *end;
int i = 0, pos = 0, shift;
u_int val, shifted_val, first = 0;
@@ -138,7 +139,7 @@ chunk_t asn1_oid_from_string(char *str)
while (enumerator->enumerate(enumerator, &str))
{
val = strtoul(str, &end, 10);
- if (end == str || pos > countof(buf))
+ if (end == str || pos > buf_len-4)
{
pos = 0;
break;
@@ -175,8 +176,9 @@ chunk_t asn1_oid_from_string(char *str)
*/
char *asn1_oid_to_string(chunk_t oid)
{
- char buf[64], *pos = buf;
- int len;
+ size_t len = 64;
+ char buf[len], *pos = buf;
+ int written;
u_int val;
if (!oid.len)
@@ -184,13 +186,14 @@ char *asn1_oid_to_string(chunk_t oid)
return NULL;
}
val = oid.ptr[0] / 40;
- len = snprintf(buf, sizeof(buf), "%u.%u", val, oid.ptr[0] - val * 40);
+ written = snprintf(buf, len, "%u.%u", val, oid.ptr[0] - val * 40);
oid = chunk_skip(oid, 1);
- if (len < 0 || len >= sizeof(buf))
+ if (written < 0 || written >= len)
{
return NULL;
}
- pos += len;
+ pos += written;
+ len -= written;
val = 0;
while (oid.len)
@@ -199,12 +202,13 @@ char *asn1_oid_to_string(chunk_t oid)
if (oid.ptr[0] < 128)
{
- len = snprintf(pos, sizeof(buf) + buf - pos, ".%u", val);
- if (len < 0 || len >= sizeof(buf) + buf - pos)
+ written = snprintf(pos, len, ".%u", val);
+ if (written < 0 || written >= len)
{
return NULL;
}
- pos += len;
+ pos += written;
+ len -= written;
val = 0;
}
oid = chunk_skip(oid, 1);
@@ -296,7 +300,7 @@ int asn1_unwrap(chunk_t *blob, chunk_t *inner)
else
{ /* composite length, determine number of length octets */
len &= 0x7f;
- if (len == 0 || len > sizeof(res.len))
+ if (len == 0 || len > blob->len || len > sizeof(res.len))
{
return ASN1_INVALID;
}
@@ -389,8 +393,8 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
tm_year += (tm_year < 50) ? 2000 : 1900;
}
- /* prevent large 32 bit integer overflows */
- if (sizeof(time_t) == 4 && tm_year > 2038)
+ /* prevent obvious 32 bit integer overflows */
+ if (sizeof(time_t) == 4 && (tm_year > 2038 || tm_year < 1901))
{
return TIME_32_BIT_SIGNED_MAX;
}
@@ -398,13 +402,24 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
/* representation of months as 0..11*/
if (tm_mon < 1 || tm_mon > 12)
{
- return 0; /* error in month format */
+ return 0;
}
tm_mon--;
/* representation of days as 0..30 */
+ if (tm_day < 1 || tm_day > 31)
+ { /* we don't actually validate the day in relation to tm_year/tm_mon */
+ return 0;
+ }
tm_day--;
+ if (tm_hour < 0 || tm_hour > 23 ||
+ tm_min < 0 || tm_min > 59 ||
+ tm_sec < 0 || tm_sec > 60 /* allow leap seconds */)
+ {
+ return 0;
+ }
+
/* number of leap years between last year and 1970? */
tm_leap_4 = (tm_year - 1) / 4;
tm_leap_100 = tm_leap_4 / 25;
@@ -420,8 +435,20 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
tm_days = 365 * (tm_year - 1970) + days[tm_mon] + tm_day + tm_leap;
tm_secs = 60 * (60 * (24 * tm_days + tm_hour) + tm_min) + tm_sec - tz_offset;
- /* has a 32 bit signed integer overflow occurred? */
- return (tm_secs < 0) ? TIME_32_BIT_SIGNED_MAX : tm_secs;
+ if (sizeof(time_t) == 4)
+ { /* has a 32 bit signed integer overflow occurred? */
+ if (tm_year > 1970 && tm_secs < 0)
+ { /* depending on the time zone, the first days in 1970 may result in
+ * a negative value, but dates after 1970 never will */
+ return TIME_32_BIT_SIGNED_MAX;
+ }
+ if (tm_year < 1969 && tm_secs > 0)
+ { /* similarly, tm_secs is not positive for dates before 1970, except
+ * for the last days in 1969, depending on the time zone */
+ return TIME_32_BIT_SIGNED_MAX;
+ }
+ }
+ return tm_secs;
}
/**
@@ -537,7 +564,7 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c
len = asn1_length(object);
- if (len == ASN1_INVALID_LENGTH || object->len < len)
+ if (len == ASN1_INVALID_LENGTH)
{
DBG2(DBG_ASN, "L%d - %s: length of ASN.1 object invalid or too large",
level, name);
@@ -675,7 +702,9 @@ bool asn1_is_printablestring(chunk_t str)
for (i = 0; i < str.len; i++)
{
if (strchr(printablestring_charset, str.ptr[i]) == NULL)
+ {
return FALSE;
+ }
}
return TRUE;
}
@@ -781,10 +810,17 @@ chunk_t asn1_integer(const char *mode, chunk_t content)
chunk_t object;
size_t len;
u_char *pos;
+ bool move;
+
if (content.len == 0)
{ /* make sure 0 is encoded properly */
content = chunk_from_chars(0x00);
+ move = FALSE;
+ }
+ else
+ {
+ move = (*mode == 'm');
}
/* ASN.1 integers must be positive numbers in two's complement */
@@ -794,11 +830,9 @@ chunk_t asn1_integer(const char *mode, chunk_t content)
{
*pos++ = 0x00;
}
- if (len)
- {
- memcpy(pos, content.ptr, content.len);
- }
- if (*mode == 'm')
+ memcpy(pos, content.ptr, content.len);
+
+ if (move)
{
free(content.ptr);
}