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.c311
1 files changed, 94 insertions, 217 deletions
diff --git a/src/libstrongswan/asn1/asn1.c b/src/libstrongswan/asn1/asn1.c
index ec46b165b..763caafc4 100644
--- a/src/libstrongswan/asn1/asn1.c
+++ b/src/libstrongswan/asn1/asn1.c
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <string.h>
#include <time.h>
-#include <pthread.h>
#include <utils.h>
#include <debug.h>
@@ -28,161 +27,34 @@
#include "asn1_parser.h"
/**
- * some common prefabricated ASN.1 constants
+ * Commonly used ASN1 values.
*/
-static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 };
-static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 };
-static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 };
-
-const chunk_t ASN1_INTEGER_0 = chunk_from_buf(ASN1_INTEGER_0_str);
-const chunk_t ASN1_INTEGER_1 = chunk_from_buf(ASN1_INTEGER_1_str);
-const chunk_t ASN1_INTEGER_2 = chunk_from_buf(ASN1_INTEGER_2_str);
-
-/**
- * some popular algorithmIdentifiers
- */
-
-static u_char ASN1_md2_id_str[] = {
- 0x30, 0x0c,
- 0x06, 0x08,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x02,
- 0x05,0x00,
-};
-
-static u_char ASN1_md5_id_str[] = {
- 0x30, 0x0C,
- 0x06, 0x08,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha1_id_str[] = {
- 0x30, 0x09,
- 0x06, 0x05,
- 0x2B, 0x0E,0x03, 0x02, 0x1A,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha256_id_str[] = {
- 0x30, 0x0d,
- 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha384_id_str[] = {
- 0x30, 0x0d,
- 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha512_id_str[] = {
- 0x30, 0x0d,
- 0x06, 0x09,
- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
- 0x05,0x00
-};
-
-static u_char ASN1_md2WithRSA_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02,
- 0x05, 0x00
-};
-
-static u_char ASN1_md5WithRSA_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha1WithRSA_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha256WithRSA_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha384WithRSA_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C,
- 0x05, 0x00
-};
-
-static u_char ASN1_sha512WithRSA_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D,
- 0x05, 0x00
-};
-
-static u_char ASN1_rsaEncryption_id_str[] = {
- 0x30, 0x0D,
- 0x06, 0x09,
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
- 0x05, 0x00
-};
-
-static const chunk_t ASN1_md2_id = chunk_from_buf(ASN1_md2_id_str);
-static const chunk_t ASN1_md5_id = chunk_from_buf(ASN1_md5_id_str);
-static const chunk_t ASN1_sha1_id = chunk_from_buf(ASN1_sha1_id_str);
-static const chunk_t ASN1_sha256_id = chunk_from_buf(ASN1_sha256_id_str);
-static const chunk_t ASN1_sha384_id = chunk_from_buf(ASN1_sha384_id_str);
-static const chunk_t ASN1_sha512_id = chunk_from_buf(ASN1_sha512_id_str);
-static const chunk_t ASN1_rsaEncryption_id = chunk_from_buf(ASN1_rsaEncryption_id_str);
-static const chunk_t ASN1_md2WithRSA_id = chunk_from_buf(ASN1_md2WithRSA_id_str);
-static const chunk_t ASN1_md5WithRSA_id = chunk_from_buf(ASN1_md5WithRSA_id_str);
-static const chunk_t ASN1_sha1WithRSA_id = chunk_from_buf(ASN1_sha1WithRSA_id_str);
-static const chunk_t ASN1_sha256WithRSA_id = chunk_from_buf(ASN1_sha256WithRSA_id_str);
-static const chunk_t ASN1_sha384WithRSA_id = chunk_from_buf(ASN1_sha384WithRSA_id_str);
-static const chunk_t ASN1_sha512WithRSA_id = chunk_from_buf(ASN1_sha512WithRSA_id_str);
+const chunk_t ASN1_INTEGER_0 = chunk_from_chars(0x02, 0x00);
+const chunk_t ASN1_INTEGER_1 = chunk_from_chars(0x02, 0x01, 0x01);
+const chunk_t ASN1_INTEGER_2 = chunk_from_chars(0x02, 0x01, 0x02);
/*
* Defined in header.
*/
chunk_t asn1_algorithmIdentifier(int oid)
{
+ chunk_t parameters;
+
+ /* some algorithmIdentifiers have a NULL parameters field and some do not */
switch (oid)
{
- case OID_RSA_ENCRYPTION:
- return ASN1_rsaEncryption_id;
- case OID_MD2_WITH_RSA:
- return ASN1_md2WithRSA_id;
- case OID_MD5_WITH_RSA:
- return ASN1_md5WithRSA_id;
- case OID_SHA1_WITH_RSA:
- return ASN1_sha1WithRSA_id;
- case OID_SHA256_WITH_RSA:
- return ASN1_sha256WithRSA_id;
- case OID_SHA384_WITH_RSA:
- return ASN1_sha384WithRSA_id;
- case OID_SHA512_WITH_RSA:
- return ASN1_sha512WithRSA_id;
- case OID_MD2:
- return ASN1_md2_id;
- case OID_MD5:
- return ASN1_md5_id;
- case OID_SHA1:
- return ASN1_sha1_id;
- case OID_SHA256:
- return ASN1_sha256_id;
- case OID_SHA384:
- return ASN1_sha384_id;
- case OID_SHA512:
- return ASN1_sha512_id;
+ case OID_ECDSA_WITH_SHA1:
+ case OID_ECDSA_WITH_SHA224:
+ case OID_ECDSA_WITH_SHA256:
+ case OID_ECDSA_WITH_SHA384:
+ case OID_ECDSA_WITH_SHA512:
+ parameters = chunk_empty;
+ break;
default:
- return chunk_empty;
+ parameters = asn1_simple_object(ASN1_NULL, chunk_empty);
+ break;
}
+ return asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(oid), parameters);
}
/*
@@ -191,14 +63,14 @@ chunk_t asn1_algorithmIdentifier(int oid)
int asn1_known_oid(chunk_t object)
{
int oid = 0;
-
+
while (object.len)
{
if (oid_names[oid].octet == *object.ptr)
{
if (--object.len == 0 || oid_names[oid].down == 0)
{
- return oid; /* found terminal symbol */
+ return oid; /* found terminal symbol */
}
else
{
@@ -227,17 +99,17 @@ chunk_t asn1_build_known_oid(int n)
{
chunk_t oid;
int i;
-
+
if (n < 0 || n >= OID_MAX)
{
return chunk_empty;
}
-
+
i = oid_names[n].level + 1;
oid = chunk_alloc(2 + i);
oid.ptr[0] = ASN1_OID;
oid.ptr[1] = i;
-
+
do
{
if (oid_names[n].level >= i)
@@ -248,7 +120,7 @@ chunk_t asn1_build_known_oid(int n)
oid.ptr[--i + 2] = oid_names[n--].octet;
}
while (i > 0);
-
+
return oid;
}
@@ -259,18 +131,18 @@ size_t asn1_length(chunk_t *blob)
{
u_char n;
size_t len;
-
+
if (blob->len < 2)
{
DBG2("insufficient number of octets to parse ASN.1 length");
return ASN1_INVALID_LENGTH;
}
-
+
/* read length field, skip tag and length */
n = blob->ptr[1];
*blob = chunk_skip(*blob, 2);
-
- if ((n & 0x80) == 0)
+
+ if ((n & 0x80) == 0)
{ /* single length octet */
if (n > blob->len)
{
@@ -279,25 +151,25 @@ size_t asn1_length(chunk_t *blob)
}
return n;
}
-
+
/* composite length, determine number of length octets */
n &= 0x7f;
-
+
if (n == 0 || n > blob->len)
{
DBG2("number of length octets invalid");
return ASN1_INVALID_LENGTH;
}
-
+
if (n > sizeof(len))
{
- DBG2("number of length octets is larger than limit of %d octets",
+ DBG2("number of length octets is larger than limit of %d octets",
(int)sizeof(len));
return ASN1_INVALID_LENGTH;
}
-
+
len = 0;
-
+
while (n-- > 0)
{
len = 256*len + *blob->ptr++;
@@ -319,7 +191,7 @@ int asn1_unwrap(chunk_t *blob, chunk_t *inner)
chunk_t res;
u_char len;
int type;
-
+
if (blob->len < 2)
{
return ASN1_INVALID;
@@ -327,7 +199,7 @@ int asn1_unwrap(chunk_t *blob, chunk_t *inner)
type = blob->ptr[0];
len = blob->ptr[1];
*blob = chunk_skip(*blob, 2);
-
+
if ((len & 0x80) == 0)
{ /* single length octet */
res.len = len;
@@ -358,8 +230,6 @@ int asn1_unwrap(chunk_t *blob, chunk_t *inner)
return type;
}
-#define TIME_MAX 0x7fffffff
-
static const int days[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
static const int tm_leap_1970 = 477;
@@ -373,7 +243,7 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
int tz_hour, tz_min, tz_offset;
time_t tm_secs;
u_char *eot = NULL;
-
+
if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
{
tz_offset = 0; /* Zulu time with a zero time zone offset */
@@ -398,19 +268,19 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
{
return 0; /* error in time format */
}
-
+
/* parse ASN.1 time string */
{
const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
"%4d%2d%2d%2d%2d";
-
+
if (sscanf(utctime->ptr, format, &tm_year, &tm_mon, &tm_day,
&tm_hour, &tm_min) != 5)
{
return 0; /* error in [yy]yymmddhhmm time format */
}
}
-
+
/* is there a seconds field? */
if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
{
@@ -423,17 +293,17 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
{
tm_sec = 0;
}
-
+
/* representation of two-digit years */
if (type == ASN1_UTCTIME)
{
tm_year += (tm_year < 50) ? 2000 : 1900;
}
-
+
/* prevent large 32 bit integer overflows */
if (sizeof(time_t) == 4 && tm_year > 2038)
{
- return TIME_MAX;
+ return TIME_32_BIT_SIGNED_MAX;
}
/* representation of months as 0..11*/
@@ -442,7 +312,7 @@ time_t asn1_to_time(const chunk_t *utctime, asn1_t type)
return 0; /* error in month format */
}
tm_mon--;
-
+
/* representation of days as 0..30 */
tm_day--;
@@ -461,8 +331,8 @@ 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 overflow occurred? */
- return (tm_secs < 0) ? TIME_MAX : tm_secs;
+ /* has a 32 bit signed integer overflow occurred? */
+ return (tm_secs < 0) ? TIME_32_BIT_SIGNED_MAX : tm_secs;
}
/**
@@ -475,7 +345,7 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type)
char buf[BUF_LEN];
chunk_t formatted_time;
struct tm t;
-
+
gmtime_r(time, &t);
if (type == ASN1_GENERALIZEDTIME)
{
@@ -487,7 +357,7 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type)
format = "%02d%02d%02d%02d%02d%02dZ";
offset = (t.tm_year < 100)? 0 : -100;
}
- snprintf(buf, BUF_LEN, format, t.tm_year + offset,
+ snprintf(buf, BUF_LEN, format, t.tm_year + offset,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
formatted_time.ptr = buf;
formatted_time.len = strlen(buf);
@@ -500,7 +370,7 @@ chunk_t asn1_from_time(const time_t *time, asn1_t type)
void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
{
int oid;
-
+
switch (type)
{
case ASN1_OID:
@@ -545,30 +415,30 @@ void asn1_debug_simple_object(chunk_t object, asn1_t type, bool private)
bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name)
{
size_t len;
-
+
/* an ASN.1 object must possess at least a tag and length field */
if (object->len < 2)
{
DBG2("L%d - %s: ASN.1 object smaller than 2 octets", level, name);
return FALSE;
}
-
+
if (*object->ptr != type)
{
DBG2("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
level, name, type, *object->ptr);
return FALSE;
}
-
+
len = asn1_length(object);
-
+
if (len == ASN1_INVALID_LENGTH || object->len < len)
{
DBG2("L%d - %s: length of ASN.1 object invalid or too large",
level, name);
return FALSE;
}
-
+
DBG2("L%d - %s:", level, name);
asn1_debug_simple_object(*object, type, FALSE);
return TRUE;
@@ -578,11 +448,11 @@ bool asn1_parse_simple_object(chunk_t *object, asn1_t type, u_int level, const c
* ASN.1 definition of an algorithmIdentifier
*/
static const asn1Object_t algorithmIdentifierObjects[] = {
- { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
- { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
- { 1, "parameters", ASN1_EOC, ASN1_RAW|ASN1_OPT }, /* 2 */
- { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
- { 0, "exit", ASN1_EOC, ASN1_EXIT }
+ { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
+ { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
+ { 1, "parameters", ASN1_EOC, ASN1_RAW|ASN1_OPT }, /* 2 */
+ { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define ALGORITHM_ID_ALG 1
#define ALGORITHM_ID_PARAMETERS 2
@@ -596,10 +466,10 @@ int asn1_parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters
chunk_t object;
int objectID;
int alg = OID_UNKNOWN;
-
+
parser = asn1_parser_create(algorithmIdentifierObjects, blob);
parser->set_top_level(parser, level0);
-
+
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID)
@@ -629,7 +499,7 @@ bool is_asn1(chunk_t blob)
u_int len;
u_char tag = *blob.ptr;
- if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
+ if (tag != ASN1_SEQUENCE && tag != ASN1_SET && tag != ASN1_OCTET_STRING)
{
DBG2(" file content is not binary ASN.1");
return FALSE;
@@ -661,7 +531,7 @@ bool asn1_is_printablestring(chunk_t str)
const char printablestring_charset[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
u_int i;
-
+
for (i = 0; i < str.len; i++)
{
if (strchr(printablestring_charset, str.ptr[i]) == NULL)
@@ -711,24 +581,24 @@ u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen)
u_char length_buf[4];
chunk_t length = { length_buf, 0 };
u_char *pos;
-
+
/* code the asn.1 length field */
asn1_code_length(datalen, &length);
-
+
/* allocate memory for the asn.1 TLV object */
object->len = 1 + length.len + datalen;
object->ptr = malloc(object->len);
-
+
/* set position pointer at the start of the object */
pos = object->ptr;
-
+
/* copy the asn.1 tag field and advance the pointer */
*pos++ = type;
-
+
/* copy the asn.1 length field and advance the pointer */
- memcpy(pos, length.ptr, length.len);
+ memcpy(pos, length.ptr, length.len);
pos += length.len;
-
+
return pos;
}
@@ -738,11 +608,11 @@ u_char* asn1_build_object(chunk_t *object, asn1_t type, size_t datalen)
chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
{
chunk_t object;
-
+
u_char *pos = asn1_build_object(&object, tag, content.len);
- memcpy(pos, content.ptr, content.len);
+ memcpy(pos, content.ptr, content.len);
pos += content.len;
-
+
return object;
}
@@ -809,8 +679,8 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
u_char *pos;
int i;
int count = strlen(mode);
-
- /* sum up lengths of individual chunks */
+
+ /* sum up lengths of individual chunks */
va_start(chunks, mode);
construct.len = 0;
for (i = 0; i < count; i++)
@@ -819,26 +689,33 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
construct.len += ch.len;
}
va_end(chunks);
-
+
/* allocate needed memory for construct */
pos = asn1_build_object(&construct, type, construct.len);
-
+
/* copy or move the chunks */
va_start(chunks, mode);
for (i = 0; i < count; i++)
{
chunk_t ch = va_arg(chunks, chunk_t);
-
+
memcpy(pos, ch.ptr, ch.len);
pos += ch.len;
- if (*mode++ == 'm')
+ switch (*mode++)
{
- free(ch.ptr);
+ case 's':
+ chunk_clear(&ch);
+ break;
+ case 'm':
+ free(ch.ptr);
+ break;
+ default:
+ break;
}
}
va_end(chunks);
-
+
return construct;
}
@@ -846,11 +723,11 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
* ASN.1 definition of time
*/
static const asn1Object_t timeObjects[] = {
- { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */
- { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
- { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */
- { 0, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
- { 0, "exit", ASN1_EOC, ASN1_EXIT }
+ { 0, "utcTime", ASN1_UTCTIME, ASN1_OPT|ASN1_BODY }, /* 0 */
+ { 0, "end opt", ASN1_EOC, ASN1_END }, /* 1 */
+ { 0, "generalizeTime", ASN1_GENERALIZEDTIME, ASN1_OPT|ASN1_BODY }, /* 2 */
+ { 0, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define TIME_UTC 0
#define TIME_GENERALIZED 2
@@ -864,10 +741,10 @@ time_t asn1_parse_time(chunk_t blob, int level0)
chunk_t object;
int objectID;
time_t utc_time = 0;
-
+
parser= asn1_parser_create(timeObjects, blob);
parser->set_top_level(parser, level0);
-
+
while (parser->iterate(parser, &objectID, &object))
{
if (objectID == TIME_UTC || objectID == TIME_GENERALIZED)