- startet importing pluto ASN1 stuff
- der PKCS#1 key loading works (as it did with der_decoder)
This commit is contained in:
+1
-1
@@ -29,7 +29,7 @@ MAIN_DIR= ./
|
||||
|
||||
LDFLAGS= -ldl -lgmp -lpthread -rdynamic
|
||||
|
||||
CFLAGS= -Icharon -Ilib -Istroke -Wall -g -fPIC -fomit-frame-pointer -DLEAK_DETECTIVE
|
||||
CFLAGS= -Icharon -Ilib -Istroke -Wall -g -fPIC -DLEAK_DETECTIVE
|
||||
|
||||
# objects is extended by each included Makefile
|
||||
CHARON_OBJS=
|
||||
|
||||
@@ -448,6 +448,8 @@ socket_t *socket_create(u_int16_t port)
|
||||
|
||||
if (build_interface_list(this, port) != SUCCESS)
|
||||
{
|
||||
this->interfaces->destroy(this->interfaces);
|
||||
free(this);
|
||||
charon->kill(charon, "could not bind any interface!");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Known bugs in charon
|
||||
======================
|
||||
|
||||
- intiating the same connection twice makes trouble.
|
||||
-
|
||||
- intiating the same connection twice makes trouble
|
||||
- leak_detective gets confused from libpthread (invalid frees)
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
+ new charon build - libstrong?
|
||||
+ transforms
|
||||
+ utils (plus host)
|
||||
- doxygen fixes (two doxyfiles?)
|
||||
- allocator cleanup (used in lib, charon and pluto(!))
|
||||
- logger reimplementation? (one logger for lib, charon, pluto)
|
||||
+ logger_manager instance in lib
|
||||
+ leak detective usable for charon and pluto and anything else
|
||||
- doxygen fixes (multiple doxyfiles?)
|
||||
- integrate asn1 parser/oid (asn1/oid)
|
||||
- integrate PEM loading (pem)
|
||||
- ... (more to come, for sure)
|
||||
- ... (more to come)
|
||||
|
||||
- ipsec.secrets parsing
|
||||
|
||||
@@ -42,3 +42,5 @@
|
||||
- delete notify, when to send?
|
||||
- notifys on connection setup failure
|
||||
- create child sa message
|
||||
|
||||
- new build environment (autotools?)
|
||||
@@ -25,3 +25,4 @@ $(BUILD_DIR)definitions.o : $(LIB_DIR)definitions.c $(LIB_DIR)definitions.h
|
||||
include $(MAIN_DIR)lib/crypto/Makefile.transforms
|
||||
include $(MAIN_DIR)lib/utils/Makefile.utils
|
||||
include $(MAIN_DIR)lib/asn1/Makefile.asn1
|
||||
include $(MAIN_DIR)lib/asn1-pluto/Makefile.asn1
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Copyright (C) 2006 Martin Willi
|
||||
# Hochschule fuer Technik Rapperswil
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at your
|
||||
# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
|
||||
ASN1_DIR= $(LIB_DIR)asn1-pluto/
|
||||
|
||||
|
||||
LIB_OBJS+= $(BUILD_DIR)oid.o
|
||||
$(BUILD_DIR)oid.o : $(ASN1_DIR)oid.c $(ASN1_DIR)oid.h
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
LIB_OBJS+= $(BUILD_DIR)asn1-pluto.o
|
||||
$(BUILD_DIR)asn1-pluto.o : $(ASN1_DIR)asn1-pluto.c $(ASN1_DIR)asn1-pluto.h
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
LIB_OBJS+= $(BUILD_DIR)pem.o
|
||||
$(BUILD_DIR)pem.o : $(ASN1_DIR)pem.c $(ASN1_DIR)pem.h
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
LIB_OBJS+= $(BUILD_DIR)ttodata.o
|
||||
$(BUILD_DIR)ttodata.o : $(ASN1_DIR)ttodata.c $(ASN1_DIR)ttodata.h
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
@@ -0,0 +1,574 @@
|
||||
/* Simple ASN.1 parser
|
||||
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
* Copyright (C) 2006 Martin Will, Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "asn1-pluto.h"
|
||||
#include "oid.h"
|
||||
|
||||
#include <utils/logger_manager.h>
|
||||
|
||||
static logger_t *logger;
|
||||
|
||||
/* Names of the months */
|
||||
static const char* months[] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
/* some common prefabricated ASN.1 constants */
|
||||
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_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_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_rsaEncryption_id_str[] = {
|
||||
0x30, 0x0D,
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00
|
||||
};
|
||||
|
||||
const chunk_t ASN1_md5_id = chunk_from_buf(ASN1_md5_id_str);
|
||||
const chunk_t ASN1_sha1_id = chunk_from_buf(ASN1_sha1_id_str);
|
||||
const chunk_t ASN1_rsaEncryption_id = chunk_from_buf(ASN1_rsaEncryption_id_str);
|
||||
const chunk_t ASN1_md5WithRSA_id = chunk_from_buf(ASN1_md5WithRSA_id_str);
|
||||
const chunk_t ASN1_sha1WithRSA_id = chunk_from_buf(ASN1_sha1WithRSA_id_str);
|
||||
|
||||
/* ASN.1 definiton 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 } /* 2 */
|
||||
};
|
||||
|
||||
#define ALGORITHM_ID_ALG 1
|
||||
#define ALGORITHM_ID_PARAMETERS 2
|
||||
#define ALGORITHM_ID_ROOF 3
|
||||
|
||||
/*
|
||||
* return the ASN.1 encoded algorithm identifier
|
||||
*/
|
||||
chunk_t asn1_algorithmIdentifier(int oid)
|
||||
{
|
||||
switch (oid)
|
||||
{
|
||||
case OID_RSA_ENCRYPTION:
|
||||
return ASN1_rsaEncryption_id;
|
||||
case OID_MD5_WITH_RSA:
|
||||
return ASN1_md5WithRSA_id;
|
||||
case OID_SHA1_WITH_RSA:
|
||||
return ASN1_sha1WithRSA_id;
|
||||
case OID_MD5:
|
||||
return ASN1_md5_id;
|
||||
case OID_SHA1:
|
||||
return ASN1_sha1_id;
|
||||
default:
|
||||
return CHUNK_INITIALIZER;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the oid is listed in the oid_names table then the corresponding
|
||||
* position in the oid_names table is returned otherwise -1 is returned
|
||||
*/
|
||||
int 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 */
|
||||
}
|
||||
else
|
||||
{
|
||||
object.ptr++; oid++; /* advance to next hex octet */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oid_names[oid].next)
|
||||
oid = oid_names[oid].next;
|
||||
else
|
||||
return OID_UNKNOWN;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes the length in bytes of an ASN.1 object
|
||||
*/
|
||||
u_int asn1_length(chunk_t *blob)
|
||||
{
|
||||
u_char n;
|
||||
size_t len;
|
||||
|
||||
/* advance from tag field on to length field */
|
||||
blob->ptr++;
|
||||
blob->len--;
|
||||
|
||||
/* read first octet of length field */
|
||||
n = *blob->ptr++;
|
||||
blob->len--;
|
||||
|
||||
if ((n & 0x80) == 0)
|
||||
{/* single length octet */
|
||||
return n;
|
||||
}
|
||||
|
||||
/* composite length, determine number of length octets */
|
||||
n &= 0x7f;
|
||||
|
||||
if (n > blob->len)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "number of length octets is larger than ASN.1 object");
|
||||
return ASN1_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
if (n > sizeof(len))
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "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++;
|
||||
blob->len--;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* determines if a character string is of type ASN.1 printableString
|
||||
*/
|
||||
bool 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)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Display a date either in local or UTC time
|
||||
* TODO: Does not seem to be thread save
|
||||
*/
|
||||
char* timetoa(const time_t *time, bool utc)
|
||||
{
|
||||
static char buf[30];
|
||||
|
||||
if (*time == 0)
|
||||
sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" ");
|
||||
else
|
||||
{
|
||||
struct tm *t = (utc)? gmtime(time) : localtime(time);
|
||||
sprintf(buf, "%s %02d %02d:%02d:%02d%s%04d",
|
||||
months[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
|
||||
(utc)?" UTC ":" ", t->tm_year + 1900);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
|
||||
*/
|
||||
time_t asn1totime(const chunk_t *utctime, asn1_t type)
|
||||
{
|
||||
struct tm t;
|
||||
time_t tz_offset;
|
||||
u_char *eot = NULL;
|
||||
|
||||
if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
|
||||
{
|
||||
tz_offset = 0; /* Zulu time with a zero time zone offset */
|
||||
}
|
||||
else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
|
||||
{
|
||||
int tz_hour, tz_min;
|
||||
|
||||
sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
|
||||
tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
|
||||
}
|
||||
else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
|
||||
{
|
||||
int tz_hour, tz_min;
|
||||
|
||||
sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
|
||||
tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; /* error in time format */
|
||||
}
|
||||
|
||||
{
|
||||
const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
|
||||
"%4d%2d%2d%2d%2d";
|
||||
|
||||
sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,
|
||||
&t.tm_hour, &t.tm_min);
|
||||
}
|
||||
|
||||
/* is there a seconds field? */
|
||||
if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
|
||||
{
|
||||
sscanf(eot-2, "%2d", &t.tm_sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
t.tm_sec = 0;
|
||||
}
|
||||
|
||||
/* representation of year */
|
||||
if (t.tm_year >= 1900)
|
||||
{
|
||||
t.tm_year -= 1900;
|
||||
}
|
||||
else if (t.tm_year >= 100)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (t.tm_year < 50)
|
||||
{
|
||||
t.tm_year += 100;
|
||||
}
|
||||
|
||||
/* representation of month 0..11*/
|
||||
t.tm_mon--;
|
||||
|
||||
/* set daylight saving time to off */
|
||||
t.tm_isdst = 0;
|
||||
|
||||
/* compensate timezone */
|
||||
|
||||
return mktime(&t) - timezone - tz_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the internal context of the ASN.1 parser
|
||||
*/
|
||||
void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit)
|
||||
{
|
||||
logger = logger_manager->get_logger(logger_manager, ASN1);
|
||||
ctx->blobs[0] = blob;
|
||||
ctx->level0 = level0;
|
||||
ctx->implicit = implicit;
|
||||
memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
|
||||
}
|
||||
|
||||
/*
|
||||
* print the value of an ASN.1 simple object
|
||||
*/
|
||||
static void debug_asn1_simple_object(chunk_t object, asn1_t type)
|
||||
{
|
||||
int oid;
|
||||
time_t time;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ASN1_OID:
|
||||
oid = known_oid(object);
|
||||
if (oid != OID_UNKNOWN)
|
||||
{
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%s'", oid_names[oid].name);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ASN1_UTF8STRING:
|
||||
case ASN1_IA5STRING:
|
||||
case ASN1_PRINTABLESTRING:
|
||||
case ASN1_T61STRING:
|
||||
case ASN1_VISIBLESTRING:
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%.*s'", (int)object.len, object.ptr);
|
||||
return;
|
||||
case ASN1_UTCTIME:
|
||||
case ASN1_GENERALIZEDTIME:
|
||||
time = asn1totime(&object, type);
|
||||
logger->log(logger, CONTROL|LEVEL1, " '%s'", timetoa(&time, TRUE));
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
logger->log_chunk(logger, RAW|LEVEL1, "", object);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses and extracts the next ASN.1 object
|
||||
*/
|
||||
bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
|
||||
{
|
||||
asn1Object_t obj = objects[*objectID];
|
||||
chunk_t *blob;
|
||||
chunk_t *blob1;
|
||||
u_char *start_ptr;
|
||||
|
||||
*object = CHUNK_INITIALIZER;
|
||||
|
||||
if (obj.flags & ASN1_END) /* end of loop or option found */
|
||||
{
|
||||
if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)
|
||||
{
|
||||
*objectID = ctx->loopAddr[obj.level]; /* another iteration */
|
||||
obj = objects[*objectID];
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->loopAddr[obj.level] = 0; /* exit loop or option*/
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*level = ctx->level0 + obj.level;
|
||||
blob = ctx->blobs + obj.level;
|
||||
blob1 = blob + 1;
|
||||
start_ptr = blob->ptr;
|
||||
|
||||
/* handle ASN.1 defaults values */
|
||||
if ((obj.flags & ASN1_DEF) && (blob->len == 0 || *start_ptr != obj.type) )
|
||||
{
|
||||
/* field is missing */
|
||||
logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", *level, obj.name);
|
||||
if (obj.type & ASN1_CONSTRUCTED)
|
||||
{
|
||||
(*objectID)++ ; /* skip context-specific tag */
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* handle ASN.1 options */
|
||||
|
||||
if ((obj.flags & ASN1_OPT)
|
||||
&& (blob->len == 0 || *start_ptr != obj.type))
|
||||
{
|
||||
/* advance to end of missing option field */
|
||||
do
|
||||
(*objectID)++;
|
||||
while (!((objects[*objectID].flags & ASN1_END)
|
||||
&& (objects[*objectID].level == obj.level)));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* an ASN.1 object must possess at least a tag and length field */
|
||||
|
||||
if (blob->len < 2)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN.1 object smaller than 2 octets",
|
||||
*level, obj.name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
blob1->len = asn1_length(blob);
|
||||
|
||||
if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "L%d - %s: length of ASN.1 object invalid or too large",
|
||||
*level, obj.name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
blob1->ptr = blob->ptr;
|
||||
blob->ptr += blob1->len;
|
||||
blob->len -= blob1->len;
|
||||
|
||||
/* return raw ASN.1 object without prior type checking */
|
||||
|
||||
if (obj.flags & ASN1_RAW)
|
||||
{
|
||||
logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", *level, obj.name);
|
||||
object->ptr = start_ptr;
|
||||
object->len = (size_t)(blob->ptr - start_ptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
|
||||
*level, obj.name, obj.type, *start_ptr);
|
||||
logger->log_bytes(logger, RAW|LEVEL1, "", start_ptr, (u_int)(blob->ptr - start_ptr));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", ctx->level0+obj.level, obj.name);
|
||||
|
||||
/* In case of "SEQUENCE OF" or "SET OF" start a loop */
|
||||
if (obj.flags & ASN1_LOOP)
|
||||
{
|
||||
if (blob1->len > 0)
|
||||
{
|
||||
/* at least one item, start the loop */
|
||||
ctx->loopAddr[obj.level] = *objectID + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no items, advance directly to end of loop */
|
||||
do
|
||||
(*objectID)++;
|
||||
while (!((objects[*objectID].flags & ASN1_END)
|
||||
&& (objects[*objectID].level == obj.level)));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.flags & ASN1_OBJ)
|
||||
{
|
||||
object->ptr = start_ptr;
|
||||
object->len = (size_t)(blob->ptr - start_ptr);
|
||||
logger->log_chunk(logger, RAW|LEVEL1, "", *object);
|
||||
}
|
||||
else if (obj.flags & ASN1_BODY)
|
||||
{
|
||||
*object = *blob1;
|
||||
debug_asn1_simple_object(*object, obj.type);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse an ASN.1 simple type
|
||||
*/
|
||||
bool parse_asn1_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)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "L%d - %s: ASN.1 object smaller than 2 octets",
|
||||
level, name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*object->ptr != type)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "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)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL1, "L%d - %s: length of ASN.1 object invalid or too large",
|
||||
level, name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
logger->log(logger, CONTROL|LEVEL1, "L%d - %s:", level, name);
|
||||
debug_asn1_simple_object(*object, type);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* extracts an algorithmIdentifier
|
||||
*/
|
||||
int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int alg = OID_UNKNOWN;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE);
|
||||
|
||||
while (objectID < ALGORITHM_ID_ROOF)
|
||||
{
|
||||
if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
|
||||
return OID_UNKNOWN;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case ALGORITHM_ID_ALG:
|
||||
alg = known_oid(object);
|
||||
break;
|
||||
case ALGORITHM_ID_PARAMETERS:
|
||||
if (parameters != NULL)
|
||||
*parameters = object;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return alg;
|
||||
}
|
||||
|
||||
/*
|
||||
* tests if a blob contains a valid ASN.1 set or sequence
|
||||
*/
|
||||
bool is_asn1(chunk_t blob)
|
||||
{
|
||||
u_int len;
|
||||
u_char tag = *blob.ptr;
|
||||
|
||||
if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL2, " file content is not binary ASN.1");
|
||||
return FALSE;
|
||||
}
|
||||
len = asn1_length(&blob);
|
||||
if (len != blob.len)
|
||||
{
|
||||
logger->log(logger, ERROR|LEVEL2, " file size does not match ASN.1 coded length");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/* Simple ASN.1 parser
|
||||
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
* Copyright (C) 2006 Martin Will, Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef _ASN1_H
|
||||
#define _ASN1_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
|
||||
/* Defines some primitive ASN1 types */
|
||||
|
||||
typedef enum {
|
||||
ASN1_EOC = 0x00,
|
||||
ASN1_BOOLEAN = 0x01,
|
||||
ASN1_INTEGER = 0x02,
|
||||
ASN1_BIT_STRING = 0x03,
|
||||
ASN1_OCTET_STRING = 0x04,
|
||||
ASN1_NULL = 0x05,
|
||||
ASN1_OID = 0x06,
|
||||
ASN1_ENUMERATED = 0x0A,
|
||||
ASN1_UTF8STRING = 0x0C,
|
||||
ASN1_NUMERICSTRING = 0x12,
|
||||
ASN1_PRINTABLESTRING = 0x13,
|
||||
ASN1_T61STRING = 0x14,
|
||||
ASN1_VIDEOTEXSTRING = 0x15,
|
||||
ASN1_IA5STRING = 0x16,
|
||||
ASN1_UTCTIME = 0x17,
|
||||
ASN1_GENERALIZEDTIME = 0x18,
|
||||
ASN1_GRAPHICSTRING = 0x19,
|
||||
ASN1_VISIBLESTRING = 0x1A,
|
||||
ASN1_GENERALSTRING = 0x1B,
|
||||
ASN1_UNIVERSALSTRING = 0x1C,
|
||||
ASN1_BMPSTRING = 0x1E,
|
||||
|
||||
ASN1_CONSTRUCTED = 0x20,
|
||||
|
||||
ASN1_SEQUENCE = 0x30,
|
||||
|
||||
ASN1_SET = 0x31,
|
||||
|
||||
ASN1_CONTEXT_S_0 = 0x80,
|
||||
ASN1_CONTEXT_S_1 = 0x81,
|
||||
ASN1_CONTEXT_S_2 = 0x82,
|
||||
ASN1_CONTEXT_S_3 = 0x83,
|
||||
ASN1_CONTEXT_S_4 = 0x84,
|
||||
ASN1_CONTEXT_S_5 = 0x85,
|
||||
ASN1_CONTEXT_S_6 = 0x86,
|
||||
ASN1_CONTEXT_S_7 = 0x87,
|
||||
ASN1_CONTEXT_S_8 = 0x88,
|
||||
|
||||
ASN1_CONTEXT_C_0 = 0xA0,
|
||||
ASN1_CONTEXT_C_1 = 0xA1,
|
||||
ASN1_CONTEXT_C_2 = 0xA2,
|
||||
ASN1_CONTEXT_C_3 = 0xA3,
|
||||
ASN1_CONTEXT_C_4 = 0xA4,
|
||||
ASN1_CONTEXT_C_5 = 0xA5
|
||||
} asn1_t;
|
||||
|
||||
/* Definition of ASN1 flags */
|
||||
|
||||
#define ASN1_NONE 0x00
|
||||
#define ASN1_DEF 0x01
|
||||
#define ASN1_OPT 0x02
|
||||
#define ASN1_LOOP 0x04
|
||||
#define ASN1_END 0x08
|
||||
#define ASN1_OBJ 0x10
|
||||
#define ASN1_BODY 0x20
|
||||
#define ASN1_RAW 0x40
|
||||
|
||||
#define ASN1_INVALID_LENGTH 0xffffffff
|
||||
|
||||
/* definition of an ASN.1 object */
|
||||
|
||||
typedef struct {
|
||||
u_int level;
|
||||
const u_char *name;
|
||||
asn1_t type;
|
||||
u_char flags;
|
||||
} asn1Object_t;
|
||||
|
||||
#define ASN1_MAX_LEVEL 10
|
||||
|
||||
typedef struct {
|
||||
bool implicit;
|
||||
u_int level0;
|
||||
u_int loopAddr[ASN1_MAX_LEVEL+1];
|
||||
chunk_t blobs[ASN1_MAX_LEVEL+2];
|
||||
} asn1_ctx_t;
|
||||
|
||||
/* some common prefabricated ASN.1 constants */
|
||||
|
||||
extern const chunk_t ASN1_INTEGER_0;
|
||||
extern const chunk_t ASN1_INTEGER_1;
|
||||
extern const chunk_t ASN1_INTEGER_2;
|
||||
|
||||
/* some popular algorithmIdentifiers */
|
||||
extern const chunk_t ASN1_md5_id;
|
||||
extern const chunk_t ASN1_sha1_id;
|
||||
extern const chunk_t ASN1_rsaEncryption_id;
|
||||
extern const chunk_t ASN1_md5WithRSA_id;
|
||||
extern const chunk_t ASN1_sha1WithRSA_id;
|
||||
|
||||
extern chunk_t asn1_algorithmIdentifier(int oid);
|
||||
extern int known_oid(chunk_t object);
|
||||
extern u_int asn1_length(chunk_t *blob);
|
||||
extern bool is_printablestring(chunk_t str);
|
||||
extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
|
||||
extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit);
|
||||
extern bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx);
|
||||
extern bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name);
|
||||
extern int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters);
|
||||
extern bool is_asn1(chunk_t blob);
|
||||
|
||||
#endif /* _ASN1_H */
|
||||
@@ -0,0 +1,194 @@
|
||||
/* List of some useful object identifiers (OIDs)
|
||||
* Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
*
|
||||
* This file has been automatically generated by the script oid.pl
|
||||
* Do not edit manually!
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "oid.h"
|
||||
|
||||
const oid_t oid_names[] = {
|
||||
{0x02, 7, 1, "ITU-T Administration" }, /* 0 */
|
||||
{ 0x82, 0, 1, "" }, /* 1 */
|
||||
{ 0x06, 0, 1, "Germany ITU-T member" }, /* 2 */
|
||||
{ 0x01, 0, 1, "Deutsche Telekom AG" }, /* 3 */
|
||||
{ 0x0A, 0, 1, "" }, /* 4 */
|
||||
{ 0x07, 0, 1, "" }, /* 5 */
|
||||
{ 0x14, 0, 0, "ND" }, /* 6 */
|
||||
{0x09, 18, 1, "data" }, /* 7 */
|
||||
{ 0x92, 0, 1, "" }, /* 8 */
|
||||
{ 0x26, 0, 1, "" }, /* 9 */
|
||||
{ 0x89, 0, 1, "" }, /* 10 */
|
||||
{ 0x93, 0, 1, "" }, /* 11 */
|
||||
{ 0xF2, 0, 1, "" }, /* 12 */
|
||||
{ 0x2C, 0, 1, "" }, /* 13 */
|
||||
{ 0x64, 0, 1, "pilot" }, /* 14 */
|
||||
{ 0x01, 0, 1, "pilotAttributeType" }, /* 15 */
|
||||
{ 0x01, 17, 0, "UID" }, /* 16 */
|
||||
{ 0x19, 0, 0, "DC" }, /* 17 */
|
||||
{0x55, 51, 1, "X.500" }, /* 18 */
|
||||
{ 0x04, 36, 1, "X.509" }, /* 19 */
|
||||
{ 0x03, 21, 0, "CN" }, /* 20 */
|
||||
{ 0x04, 22, 0, "S" }, /* 21 */
|
||||
{ 0x05, 23, 0, "SN" }, /* 22 */
|
||||
{ 0x06, 24, 0, "C" }, /* 23 */
|
||||
{ 0x07, 25, 0, "L" }, /* 24 */
|
||||
{ 0x08, 26, 0, "ST" }, /* 25 */
|
||||
{ 0x0A, 27, 0, "O" }, /* 26 */
|
||||
{ 0x0B, 28, 0, "OU" }, /* 27 */
|
||||
{ 0x0C, 29, 0, "T" }, /* 28 */
|
||||
{ 0x0D, 30, 0, "D" }, /* 29 */
|
||||
{ 0x24, 31, 0, "userCertificate" }, /* 30 */
|
||||
{ 0x29, 32, 0, "N" }, /* 31 */
|
||||
{ 0x2A, 33, 0, "G" }, /* 32 */
|
||||
{ 0x2B, 34, 0, "I" }, /* 33 */
|
||||
{ 0x2D, 35, 0, "ID" }, /* 34 */
|
||||
{ 0x48, 0, 0, "role" }, /* 35 */
|
||||
{ 0x1D, 0, 1, "id-ce" }, /* 36 */
|
||||
{ 0x09, 38, 0, "subjectDirectoryAttrs" }, /* 37 */
|
||||
{ 0x0E, 39, 0, "subjectKeyIdentifier" }, /* 38 */
|
||||
{ 0x0F, 40, 0, "keyUsage" }, /* 39 */
|
||||
{ 0x10, 41, 0, "privateKeyUsagePeriod" }, /* 40 */
|
||||
{ 0x11, 42, 0, "subjectAltName" }, /* 41 */
|
||||
{ 0x12, 43, 0, "issuerAltName" }, /* 42 */
|
||||
{ 0x13, 44, 0, "basicConstraints" }, /* 43 */
|
||||
{ 0x15, 45, 0, "reasonCode" }, /* 44 */
|
||||
{ 0x1F, 46, 0, "crlDistributionPoints" }, /* 45 */
|
||||
{ 0x20, 47, 0, "certificatePolicies" }, /* 46 */
|
||||
{ 0x23, 48, 0, "authorityKeyIdentifier" }, /* 47 */
|
||||
{ 0x25, 49, 0, "extendedKeyUsage" }, /* 48 */
|
||||
{ 0x37, 50, 0, "targetInformation" }, /* 49 */
|
||||
{ 0x38, 0, 0, "noRevAvail" }, /* 50 */
|
||||
{0x2A, 88, 1, "" }, /* 51 */
|
||||
{ 0x86, 0, 1, "" }, /* 52 */
|
||||
{ 0x48, 0, 1, "" }, /* 53 */
|
||||
{ 0x86, 0, 1, "" }, /* 54 */
|
||||
{ 0xF7, 0, 1, "" }, /* 55 */
|
||||
{ 0x0D, 0, 1, "RSADSI" }, /* 56 */
|
||||
{ 0x01, 83, 1, "PKCS" }, /* 57 */
|
||||
{ 0x01, 66, 1, "PKCS-1" }, /* 58 */
|
||||
{ 0x01, 60, 0, "rsaEncryption" }, /* 59 */
|
||||
{ 0x02, 61, 0, "md2WithRSAEncryption" }, /* 60 */
|
||||
{ 0x04, 62, 0, "md5WithRSAEncryption" }, /* 61 */
|
||||
{ 0x05, 63, 0, "sha-1WithRSAEncryption" }, /* 62 */
|
||||
{ 0x0B, 64, 0, "sha256WithRSAEncryption"}, /* 63 */
|
||||
{ 0x0C, 65, 0, "sha384WithRSAEncryption"}, /* 64 */
|
||||
{ 0x0D, 0, 0, "sha512WithRSAEncryption"}, /* 65 */
|
||||
{ 0x07, 73, 1, "PKCS-7" }, /* 66 */
|
||||
{ 0x01, 68, 0, "data" }, /* 67 */
|
||||
{ 0x02, 69, 0, "signedData" }, /* 68 */
|
||||
{ 0x03, 70, 0, "envelopedData" }, /* 69 */
|
||||
{ 0x04, 71, 0, "signedAndEnvelopedData" }, /* 70 */
|
||||
{ 0x05, 72, 0, "digestedData" }, /* 71 */
|
||||
{ 0x06, 0, 0, "encryptedData" }, /* 72 */
|
||||
{ 0x09, 0, 1, "PKCS-9" }, /* 73 */
|
||||
{ 0x01, 75, 0, "E" }, /* 74 */
|
||||
{ 0x02, 76, 0, "unstructuredName" }, /* 75 */
|
||||
{ 0x03, 77, 0, "contentType" }, /* 76 */
|
||||
{ 0x04, 78, 0, "messageDigest" }, /* 77 */
|
||||
{ 0x05, 79, 0, "signingTime" }, /* 78 */
|
||||
{ 0x06, 80, 0, "counterSignature" }, /* 79 */
|
||||
{ 0x07, 81, 0, "challengePassword" }, /* 80 */
|
||||
{ 0x08, 82, 0, "unstructuredAddress" }, /* 81 */
|
||||
{ 0x0E, 0, 0, "extensionRequest" }, /* 82 */
|
||||
{ 0x02, 86, 1, "digestAlgorithm" }, /* 83 */
|
||||
{ 0x02, 85, 0, "md2" }, /* 84 */
|
||||
{ 0x05, 0, 0, "md5" }, /* 85 */
|
||||
{ 0x03, 0, 1, "encryptionAlgorithm" }, /* 86 */
|
||||
{ 0x07, 0, 0, "3des-ede-cbc" }, /* 87 */
|
||||
{0x2B, 149, 1, "" }, /* 88 */
|
||||
{ 0x06, 136, 1, "dod" }, /* 89 */
|
||||
{ 0x01, 0, 1, "internet" }, /* 90 */
|
||||
{ 0x04, 105, 1, "private" }, /* 91 */
|
||||
{ 0x01, 0, 1, "enterprise" }, /* 92 */
|
||||
{ 0x82, 98, 1, "" }, /* 93 */
|
||||
{ 0x37, 0, 1, "Microsoft" }, /* 94 */
|
||||
{ 0x0A, 0, 1, "" }, /* 95 */
|
||||
{ 0x03, 0, 1, "" }, /* 96 */
|
||||
{ 0x03, 0, 0, "msSGC" }, /* 97 */
|
||||
{ 0x89, 0, 1, "" }, /* 98 */
|
||||
{ 0x31, 0, 1, "" }, /* 99 */
|
||||
{ 0x01, 0, 1, "" }, /* 100 */
|
||||
{ 0x01, 0, 1, "" }, /* 101 */
|
||||
{ 0x02, 0, 1, "" }, /* 102 */
|
||||
{ 0x02, 104, 0, "" }, /* 103 */
|
||||
{ 0x4B, 0, 0, "TCGID" }, /* 104 */
|
||||
{ 0x05, 0, 1, "security" }, /* 105 */
|
||||
{ 0x05, 0, 1, "mechanisms" }, /* 106 */
|
||||
{ 0x07, 0, 1, "id-pkix" }, /* 107 */
|
||||
{ 0x01, 110, 1, "id-pe" }, /* 108 */
|
||||
{ 0x01, 0, 0, "authorityInfoAccess" }, /* 109 */
|
||||
{ 0x03, 120, 1, "id-kp" }, /* 110 */
|
||||
{ 0x01, 112, 0, "serverAuth" }, /* 111 */
|
||||
{ 0x02, 113, 0, "clientAuth" }, /* 112 */
|
||||
{ 0x03, 114, 0, "codeSigning" }, /* 113 */
|
||||
{ 0x04, 115, 0, "emailProtection" }, /* 114 */
|
||||
{ 0x05, 116, 0, "ipsecEndSystem" }, /* 115 */
|
||||
{ 0x06, 117, 0, "ipsecTunnel" }, /* 116 */
|
||||
{ 0x07, 118, 0, "ipsecUser" }, /* 117 */
|
||||
{ 0x08, 119, 0, "timeStamping" }, /* 118 */
|
||||
{ 0x09, 0, 0, "ocspSigning" }, /* 119 */
|
||||
{ 0x08, 122, 1, "id-otherNames" }, /* 120 */
|
||||
{ 0x05, 0, 0, "xmppAddr" }, /* 121 */
|
||||
{ 0x0A, 127, 1, "id-aca" }, /* 122 */
|
||||
{ 0x01, 124, 0, "authenticationInfo" }, /* 123 */
|
||||
{ 0x02, 125, 0, "accessIdentity" }, /* 124 */
|
||||
{ 0x03, 126, 0, "chargingIdentity" }, /* 125 */
|
||||
{ 0x04, 0, 0, "group" }, /* 126 */
|
||||
{ 0x30, 0, 1, "id-ad" }, /* 127 */
|
||||
{ 0x01, 0, 1, "ocsp" }, /* 128 */
|
||||
{ 0x01, 130, 0, "basic" }, /* 129 */
|
||||
{ 0x02, 131, 0, "nonce" }, /* 130 */
|
||||
{ 0x03, 132, 0, "crl" }, /* 131 */
|
||||
{ 0x04, 133, 0, "response" }, /* 132 */
|
||||
{ 0x05, 134, 0, "noCheck" }, /* 133 */
|
||||
{ 0x06, 135, 0, "archiveCutoff" }, /* 134 */
|
||||
{ 0x07, 0, 0, "serviceLocator" }, /* 135 */
|
||||
{ 0x0E, 142, 1, "oiw" }, /* 136 */
|
||||
{ 0x03, 0, 1, "secsig" }, /* 137 */
|
||||
{ 0x02, 0, 1, "algorithms" }, /* 138 */
|
||||
{ 0x07, 140, 0, "des-cbc" }, /* 139 */
|
||||
{ 0x1A, 141, 0, "sha-1" }, /* 140 */
|
||||
{ 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 141 */
|
||||
{ 0x24, 0, 1, "TeleTrusT" }, /* 142 */
|
||||
{ 0x03, 0, 1, "algorithm" }, /* 143 */
|
||||
{ 0x03, 0, 1, "signatureAlgorithm" }, /* 144 */
|
||||
{ 0x01, 0, 1, "rsaSignature" }, /* 145 */
|
||||
{ 0x02, 147, 0, "rsaSigWithripemd160" }, /* 146 */
|
||||
{ 0x03, 148, 0, "rsaSigWithripemd128" }, /* 147 */
|
||||
{ 0x04, 0, 0, "rsaSigWithripemd256" }, /* 148 */
|
||||
{0x60, 0, 1, "" }, /* 149 */
|
||||
{ 0x86, 0, 1, "" }, /* 150 */
|
||||
{ 0x48, 0, 1, "" }, /* 151 */
|
||||
{ 0x01, 0, 1, "organization" }, /* 152 */
|
||||
{ 0x65, 160, 1, "gov" }, /* 153 */
|
||||
{ 0x03, 0, 1, "csor" }, /* 154 */
|
||||
{ 0x04, 0, 1, "nistalgorithm" }, /* 155 */
|
||||
{ 0x02, 0, 1, "hashalgs" }, /* 156 */
|
||||
{ 0x01, 158, 0, "id-SHA-256" }, /* 157 */
|
||||
{ 0x02, 159, 0, "id-SHA-384" }, /* 158 */
|
||||
{ 0x03, 0, 0, "id-SHA-512" }, /* 159 */
|
||||
{ 0x86, 0, 1, "" }, /* 160 */
|
||||
{ 0xf8, 0, 1, "" }, /* 161 */
|
||||
{ 0x42, 171, 1, "netscape" }, /* 162 */
|
||||
{ 0x01, 169, 1, "" }, /* 163 */
|
||||
{ 0x01, 165, 0, "nsCertType" }, /* 164 */
|
||||
{ 0x03, 166, 0, "nsRevocationUrl" }, /* 165 */
|
||||
{ 0x04, 167, 0, "nsCaRevocationUrl" }, /* 166 */
|
||||
{ 0x08, 168, 0, "nsCaPolicyUrl" }, /* 167 */
|
||||
{ 0x0d, 0, 0, "nsComment" }, /* 168 */
|
||||
{ 0x04, 0, 1, "policy" }, /* 169 */
|
||||
{ 0x01, 0, 0, "nsSGC" }, /* 170 */
|
||||
{ 0x45, 0, 1, "verisign" }, /* 171 */
|
||||
{ 0x01, 0, 1, "pki" }, /* 172 */
|
||||
{ 0x09, 0, 1, "attributes" }, /* 173 */
|
||||
{ 0x02, 175, 0, "messageType" }, /* 174 */
|
||||
{ 0x03, 176, 0, "pkiStatus" }, /* 175 */
|
||||
{ 0x04, 177, 0, "failInfo" }, /* 176 */
|
||||
{ 0x05, 178, 0, "senderNonce" }, /* 177 */
|
||||
{ 0x06, 179, 0, "recipientNonce" }, /* 178 */
|
||||
{ 0x07, 180, 0, "transID" }, /* 179 */
|
||||
{ 0x08, 0, 0, "extensionReq" } /* 180 */
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Object identifiers (OIDs) used by FreeS/WAN
|
||||
* Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
*
|
||||
* This file has been automatically generated by the script oid.pl
|
||||
* Do not edit manually!
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u_char octet;
|
||||
u_int next;
|
||||
u_int down;
|
||||
const u_char *name;
|
||||
} oid_t;
|
||||
|
||||
extern const oid_t oid_names[];
|
||||
|
||||
#define OID_UNKNOWN -1
|
||||
#define OID_ROLE 35
|
||||
#define OID_SUBJECT_KEY_ID 38
|
||||
#define OID_SUBJECT_ALT_NAME 41
|
||||
#define OID_BASIC_CONSTRAINTS 43
|
||||
#define OID_CRL_REASON_CODE 44
|
||||
#define OID_CRL_DISTRIBUTION_POINTS 45
|
||||
#define OID_AUTHORITY_KEY_ID 47
|
||||
#define OID_EXTENDED_KEY_USAGE 48
|
||||
#define OID_TARGET_INFORMATION 49
|
||||
#define OID_NO_REV_AVAIL 50
|
||||
#define OID_RSA_ENCRYPTION 59
|
||||
#define OID_MD2_WITH_RSA 60
|
||||
#define OID_MD5_WITH_RSA 61
|
||||
#define OID_SHA1_WITH_RSA 62
|
||||
#define OID_SHA256_WITH_RSA 63
|
||||
#define OID_SHA384_WITH_RSA 64
|
||||
#define OID_SHA512_WITH_RSA 65
|
||||
#define OID_PKCS7_DATA 67
|
||||
#define OID_PKCS7_SIGNED_DATA 68
|
||||
#define OID_PKCS7_ENVELOPED_DATA 69
|
||||
#define OID_PKCS7_SIGNED_ENVELOPED_DATA 70
|
||||
#define OID_PKCS7_DIGESTED_DATA 71
|
||||
#define OID_PKCS7_ENCRYPTED_DATA 72
|
||||
#define OID_PKCS9_EMAIL 74
|
||||
#define OID_PKCS9_CONTENT_TYPE 76
|
||||
#define OID_PKCS9_MESSAGE_DIGEST 77
|
||||
#define OID_PKCS9_SIGNING_TIME 78
|
||||
#define OID_MD2 84
|
||||
#define OID_MD5 85
|
||||
#define OID_3DES_EDE_CBC 87
|
||||
#define OID_AUTHORITY_INFO_ACCESS 109
|
||||
#define OID_OCSP_SIGNING 119
|
||||
#define OID_XMPP_ADDR 121
|
||||
#define OID_AUTHENTICATION_INFO 123
|
||||
#define OID_ACCESS_IDENTITY 124
|
||||
#define OID_CHARGING_IDENTITY 125
|
||||
#define OID_GROUP 126
|
||||
#define OID_OCSP 128
|
||||
#define OID_BASIC 129
|
||||
#define OID_NONCE 130
|
||||
#define OID_CRL 131
|
||||
#define OID_RESPONSE 132
|
||||
#define OID_NO_CHECK 133
|
||||
#define OID_ARCHIVE_CUTOFF 134
|
||||
#define OID_SERVICE_LOCATOR 135
|
||||
#define OID_DES_CBC 139
|
||||
#define OID_SHA1 140
|
||||
#define OID_SHA1_WITH_RSA_OIW 141
|
||||
#define OID_NS_REVOCATION_URL 165
|
||||
#define OID_NS_CA_REVOCATION_URL 166
|
||||
#define OID_NS_CA_POLICY_URL 167
|
||||
#define OID_NS_COMMENT 168
|
||||
#define OID_PKI_MESSAGE_TYPE 174
|
||||
#define OID_PKI_STATUS 175
|
||||
#define OID_PKI_FAIL_INFO 176
|
||||
#define OID_PKI_SENDER_NONCE 177
|
||||
#define OID_PKI_RECIPIENT_NONCE 178
|
||||
#define OID_PKI_TRANS_ID 179
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/perl
|
||||
# Generates oid.h and oid.c out of oid.txt
|
||||
# Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at your
|
||||
# option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
|
||||
$copyright="Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur";
|
||||
$automatic="This file has been automatically generated by the script oid.pl";
|
||||
$warning="Do not edit manually!";
|
||||
|
||||
print "oid.pl generating oid.h and oid.c\n";
|
||||
|
||||
# Generate oid.h
|
||||
|
||||
open(OID_H, ">oid.h")
|
||||
or die "could not open 'oid.h': $!";
|
||||
|
||||
print OID_H "/* Object identifiers (OIDs) used by FreeS/WAN\n",
|
||||
" * ", $copyright, "\n",
|
||||
" * \n",
|
||||
" * ", $automatic, "\n",
|
||||
" * ", $warning, "\n",
|
||||
" */\n\n",
|
||||
"typedef struct {\n",
|
||||
" u_char octet;\n",
|
||||
" u_int next;\n",
|
||||
" u_int down;\n",
|
||||
" const u_char *name;\n",
|
||||
"} oid_t;\n",
|
||||
"\n",
|
||||
"extern const oid_t oid_names[];\n",
|
||||
"\n",
|
||||
"#define OID_UNKNOWN -1\n";
|
||||
|
||||
# parse oid.txt
|
||||
|
||||
open(SRC, "<oid.txt")
|
||||
or die "could not open 'oid.txt': $!";
|
||||
|
||||
$counter = 0;
|
||||
$max_name = 0;
|
||||
$max_order = 0;
|
||||
|
||||
while ($line = <SRC>)
|
||||
{
|
||||
$line =~ m/( *?)(0x\w{2})\s+(".*?")[ \t]*?([\w_]*?)\Z/;
|
||||
|
||||
@order[$counter] = length($1);
|
||||
@octet[$counter] = $2;
|
||||
@name[$counter] = $3;
|
||||
|
||||
if (length($1) > $max_order)
|
||||
{
|
||||
$max_order = length($1);
|
||||
}
|
||||
if (length($3) > $max_name)
|
||||
{
|
||||
$max_name = length($3);
|
||||
}
|
||||
if (length($4) > 0)
|
||||
{
|
||||
printf OID_H "#define %s%s%d\n", $4, "\t" x ((39-length($4))/8), $counter;
|
||||
}
|
||||
$counter++;
|
||||
}
|
||||
|
||||
close SRC;
|
||||
close OID_H;
|
||||
|
||||
# Generate oid.c
|
||||
|
||||
open(OID_C, ">oid.c")
|
||||
or die "could not open 'oid.c': $!";
|
||||
|
||||
print OID_C "/* List of some useful object identifiers (OIDs)\n",
|
||||
" * ", $copyright, "\n",
|
||||
" * \n",
|
||||
" * ", $automatic, "\n",
|
||||
" * ", $warning, "\n",
|
||||
" */\n",
|
||||
"\n",
|
||||
"#include <stdlib.h>\n",
|
||||
"\n",
|
||||
"#include \"oid.h\"\n",
|
||||
"\n",
|
||||
"const oid_t oid_names[] = {\n";
|
||||
|
||||
for ($c = 0; $c < $counter; $c++)
|
||||
{
|
||||
$next = 0;
|
||||
|
||||
for ($d = $c+1; $d < $counter && @order[$d] >= @order[$c]; $d++)
|
||||
{
|
||||
if (@order[$d] == @order[$c])
|
||||
{
|
||||
@next[$c] = $d;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
printf OID_C " {%s%s,%s%3d, %d, %s%s}%s /* %3d */\n"
|
||||
,' ' x @order[$c]
|
||||
, @octet[$c]
|
||||
, ' ' x (1 + $max_order - @order[$c])
|
||||
, @next[$c]
|
||||
, @order[$c+1] > @order[$c]
|
||||
, @name[$c]
|
||||
, ' ' x ($max_name - length(@name[$c]))
|
||||
, $c != $counter-1 ? "," : " "
|
||||
, $c;
|
||||
}
|
||||
|
||||
print OID_C "};\n" ;
|
||||
close OID_C;
|
||||
@@ -0,0 +1,181 @@
|
||||
0x02 "ITU-T Administration"
|
||||
0x82 ""
|
||||
0x06 "Germany ITU-T member"
|
||||
0x01 "Deutsche Telekom AG"
|
||||
0x0A ""
|
||||
0x07 ""
|
||||
0x14 "ND"
|
||||
0x09 "data"
|
||||
0x92 ""
|
||||
0x26 ""
|
||||
0x89 ""
|
||||
0x93 ""
|
||||
0xF2 ""
|
||||
0x2C ""
|
||||
0x64 "pilot"
|
||||
0x01 "pilotAttributeType"
|
||||
0x01 "UID"
|
||||
0x19 "DC"
|
||||
0x55 "X.500"
|
||||
0x04 "X.509"
|
||||
0x03 "CN"
|
||||
0x04 "S"
|
||||
0x05 "SN"
|
||||
0x06 "C"
|
||||
0x07 "L"
|
||||
0x08 "ST"
|
||||
0x0A "O"
|
||||
0x0B "OU"
|
||||
0x0C "T"
|
||||
0x0D "D"
|
||||
0x24 "userCertificate"
|
||||
0x29 "N"
|
||||
0x2A "G"
|
||||
0x2B "I"
|
||||
0x2D "ID"
|
||||
0x48 "role" OID_ROLE
|
||||
0x1D "id-ce"
|
||||
0x09 "subjectDirectoryAttrs"
|
||||
0x0E "subjectKeyIdentifier" OID_SUBJECT_KEY_ID
|
||||
0x0F "keyUsage"
|
||||
0x10 "privateKeyUsagePeriod"
|
||||
0x11 "subjectAltName" OID_SUBJECT_ALT_NAME
|
||||
0x12 "issuerAltName"
|
||||
0x13 "basicConstraints" OID_BASIC_CONSTRAINTS
|
||||
0x15 "reasonCode" OID_CRL_REASON_CODE
|
||||
0x1F "crlDistributionPoints" OID_CRL_DISTRIBUTION_POINTS
|
||||
0x20 "certificatePolicies"
|
||||
0x23 "authorityKeyIdentifier" OID_AUTHORITY_KEY_ID
|
||||
0x25 "extendedKeyUsage" OID_EXTENDED_KEY_USAGE
|
||||
0x37 "targetInformation" OID_TARGET_INFORMATION
|
||||
0x38 "noRevAvail" OID_NO_REV_AVAIL
|
||||
0x2A ""
|
||||
0x86 ""
|
||||
0x48 ""
|
||||
0x86 ""
|
||||
0xF7 ""
|
||||
0x0D "RSADSI"
|
||||
0x01 "PKCS"
|
||||
0x01 "PKCS-1"
|
||||
0x01 "rsaEncryption" OID_RSA_ENCRYPTION
|
||||
0x02 "md2WithRSAEncryption" OID_MD2_WITH_RSA
|
||||
0x04 "md5WithRSAEncryption" OID_MD5_WITH_RSA
|
||||
0x05 "sha-1WithRSAEncryption" OID_SHA1_WITH_RSA
|
||||
0x0B "sha256WithRSAEncryption" OID_SHA256_WITH_RSA
|
||||
0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA
|
||||
0x0D "sha512WithRSAEncryption" OID_SHA512_WITH_RSA
|
||||
0x07 "PKCS-7"
|
||||
0x01 "data" OID_PKCS7_DATA
|
||||
0x02 "signedData" OID_PKCS7_SIGNED_DATA
|
||||
0x03 "envelopedData" OID_PKCS7_ENVELOPED_DATA
|
||||
0x04 "signedAndEnvelopedData" OID_PKCS7_SIGNED_ENVELOPED_DATA
|
||||
0x05 "digestedData" OID_PKCS7_DIGESTED_DATA
|
||||
0x06 "encryptedData" OID_PKCS7_ENCRYPTED_DATA
|
||||
0x09 "PKCS-9"
|
||||
0x01 "E" OID_PKCS9_EMAIL
|
||||
0x02 "unstructuredName"
|
||||
0x03 "contentType" OID_PKCS9_CONTENT_TYPE
|
||||
0x04 "messageDigest" OID_PKCS9_MESSAGE_DIGEST
|
||||
0x05 "signingTime" OID_PKCS9_SIGNING_TIME
|
||||
0x06 "counterSignature"
|
||||
0x07 "challengePassword"
|
||||
0x08 "unstructuredAddress"
|
||||
0x0E "extensionRequest"
|
||||
0x02 "digestAlgorithm"
|
||||
0x02 "md2" OID_MD2
|
||||
0x05 "md5" OID_MD5
|
||||
0x03 "encryptionAlgorithm"
|
||||
0x07 "3des-ede-cbc" OID_3DES_EDE_CBC
|
||||
0x2B ""
|
||||
0x06 "dod"
|
||||
0x01 "internet"
|
||||
0x04 "private"
|
||||
0x01 "enterprise"
|
||||
0x82 ""
|
||||
0x37 "Microsoft"
|
||||
0x0A ""
|
||||
0x03 ""
|
||||
0x03 "msSGC"
|
||||
0x89 ""
|
||||
0x31 ""
|
||||
0x01 ""
|
||||
0x01 ""
|
||||
0x02 ""
|
||||
0x02 ""
|
||||
0x4B "TCGID"
|
||||
0x05 "security"
|
||||
0x05 "mechanisms"
|
||||
0x07 "id-pkix"
|
||||
0x01 "id-pe"
|
||||
0x01 "authorityInfoAccess" OID_AUTHORITY_INFO_ACCESS
|
||||
0x03 "id-kp"
|
||||
0x01 "serverAuth"
|
||||
0x02 "clientAuth"
|
||||
0x03 "codeSigning"
|
||||
0x04 "emailProtection"
|
||||
0x05 "ipsecEndSystem"
|
||||
0x06 "ipsecTunnel"
|
||||
0x07 "ipsecUser"
|
||||
0x08 "timeStamping"
|
||||
0x09 "ocspSigning" OID_OCSP_SIGNING
|
||||
0x08 "id-otherNames"
|
||||
0x05 "xmppAddr" OID_XMPP_ADDR
|
||||
0x0A "id-aca"
|
||||
0x01 "authenticationInfo" OID_AUTHENTICATION_INFO
|
||||
0x02 "accessIdentity" OID_ACCESS_IDENTITY
|
||||
0x03 "chargingIdentity" OID_CHARGING_IDENTITY
|
||||
0x04 "group" OID_GROUP
|
||||
0x30 "id-ad"
|
||||
0x01 "ocsp" OID_OCSP
|
||||
0x01 "basic" OID_BASIC
|
||||
0x02 "nonce" OID_NONCE
|
||||
0x03 "crl" OID_CRL
|
||||
0x04 "response" OID_RESPONSE
|
||||
0x05 "noCheck" OID_NO_CHECK
|
||||
0x06 "archiveCutoff" OID_ARCHIVE_CUTOFF
|
||||
0x07 "serviceLocator" OID_SERVICE_LOCATOR
|
||||
0x0E "oiw"
|
||||
0x03 "secsig"
|
||||
0x02 "algorithms"
|
||||
0x07 "des-cbc" OID_DES_CBC
|
||||
0x1A "sha-1" OID_SHA1
|
||||
0x1D "sha-1WithRSASignature" OID_SHA1_WITH_RSA_OIW
|
||||
0x24 "TeleTrusT"
|
||||
0x03 "algorithm"
|
||||
0x03 "signatureAlgorithm"
|
||||
0x01 "rsaSignature"
|
||||
0x02 "rsaSigWithripemd160"
|
||||
0x03 "rsaSigWithripemd128"
|
||||
0x04 "rsaSigWithripemd256"
|
||||
0x60 ""
|
||||
0x86 ""
|
||||
0x48 ""
|
||||
0x01 "organization"
|
||||
0x65 "gov"
|
||||
0x03 "csor"
|
||||
0x04 "nistalgorithm"
|
||||
0x02 "hashalgs"
|
||||
0x01 "id-SHA-256"
|
||||
0x02 "id-SHA-384"
|
||||
0x03 "id-SHA-512"
|
||||
0x86 ""
|
||||
0xf8 ""
|
||||
0x42 "netscape"
|
||||
0x01 ""
|
||||
0x01 "nsCertType"
|
||||
0x03 "nsRevocationUrl" OID_NS_REVOCATION_URL
|
||||
0x04 "nsCaRevocationUrl" OID_NS_CA_REVOCATION_URL
|
||||
0x08 "nsCaPolicyUrl" OID_NS_CA_POLICY_URL
|
||||
0x0d "nsComment" OID_NS_COMMENT
|
||||
0x04 "policy"
|
||||
0x01 "nsSGC"
|
||||
0x45 "verisign"
|
||||
0x01 "pki"
|
||||
0x09 "attributes"
|
||||
0x02 "messageType" OID_PKI_MESSAGE_TYPE
|
||||
0x03 "pkiStatus" OID_PKI_STATUS
|
||||
0x04 "failInfo" OID_PKI_FAIL_INFO
|
||||
0x05 "senderNonce" OID_PKI_SENDER_NONCE
|
||||
0x06 "recipientNonce" OID_PKI_RECIPIENT_NONCE
|
||||
0x07 "transID" OID_PKI_TRANS_ID
|
||||
0x08 "extensionReq"
|
||||
Executable
+343
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Jan Hutter, Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "pem.h"
|
||||
#include "ttodata.h"
|
||||
|
||||
#include <crypto/hashers/hasher.h>
|
||||
#include <crypto/crypters/crypter.h>
|
||||
|
||||
|
||||
/*
|
||||
* check the presence of a pattern in a character string
|
||||
*/
|
||||
static bool present(const char* pattern, chunk_t* ch)
|
||||
{
|
||||
u_int pattern_len = strlen(pattern);
|
||||
|
||||
if (ch->len >= pattern_len && strncmp(ch->ptr, pattern, pattern_len) == 0)
|
||||
{
|
||||
ch->ptr += pattern_len;
|
||||
ch->len -= pattern_len;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* compare string with chunk
|
||||
*/
|
||||
static bool match(const char *pattern, const chunk_t *ch)
|
||||
{
|
||||
return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* find a boundary of the form -----tag name-----
|
||||
*/
|
||||
static bool find_boundary(const char* tag, chunk_t *line)
|
||||
{
|
||||
chunk_t name = CHUNK_INITIALIZER;
|
||||
|
||||
if (!present("-----", line))
|
||||
return FALSE;
|
||||
if (!present(tag, line))
|
||||
return FALSE;
|
||||
if (*line->ptr != ' ')
|
||||
return FALSE;
|
||||
line->ptr++; line->len--;
|
||||
|
||||
/* extract name */
|
||||
name.ptr = line->ptr;
|
||||
while (line->len > 0)
|
||||
{
|
||||
if (present("-----", line))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
line->ptr++; line->len--; name.len++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* eat whitespace
|
||||
*/
|
||||
static void eat_whitespace(chunk_t *src)
|
||||
{
|
||||
while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t'))
|
||||
{
|
||||
src->ptr++; src->len--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* extracts a token ending with a given termination symbol
|
||||
*/
|
||||
static bool extract_token(chunk_t *token, char termination, chunk_t *src)
|
||||
{
|
||||
u_char *eot = memchr(src->ptr, termination, src->len);
|
||||
|
||||
/* initialize empty token */
|
||||
*token = CHUNK_INITIALIZER;
|
||||
|
||||
if (eot == NULL) /* termination symbol not found */
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* extract token */
|
||||
token->ptr = src->ptr;
|
||||
token->len = (u_int)(eot - src->ptr);
|
||||
|
||||
/* advance src pointer after termination symbol */
|
||||
src->ptr = eot + 1;
|
||||
src->len -= (token->len + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* extracts a name: value pair from the PEM header
|
||||
*/
|
||||
static bool extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line)
|
||||
{
|
||||
/* extract name */
|
||||
if (!extract_token(name,':', line))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
eat_whitespace(line);
|
||||
|
||||
/* extract value */
|
||||
*value = *line;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* fetches a new line terminated by \n or \r\n
|
||||
*/
|
||||
static bool fetchline(chunk_t *src, chunk_t *line)
|
||||
{
|
||||
if (src->len == 0) /* end of src reached */
|
||||
return FALSE;
|
||||
|
||||
if (extract_token(line, '\n', src))
|
||||
{
|
||||
if (line->len > 0 && *(line->ptr + line->len -1) == '\r')
|
||||
line->len--; /* remove optional \r */
|
||||
}
|
||||
else /*last line ends without newline */
|
||||
{
|
||||
*line = *src;
|
||||
src->ptr += src->len;
|
||||
src->len = 0;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* decrypts a DES-EDE-CBC encrypted data block
|
||||
*/
|
||||
static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase)
|
||||
{
|
||||
hasher_t *hasher;
|
||||
crypter_t *crypter;
|
||||
chunk_t hash;
|
||||
chunk_t decrypted;
|
||||
chunk_t pass = {passphrase, strlen(passphrase)};
|
||||
chunk_t key = {alloca(24), 24};
|
||||
u_int8_t padding, *last_padding_pos, *first_padding_pos;
|
||||
|
||||
/* build key from passphrase and IV */
|
||||
hasher = hasher_create(HASH_MD5);
|
||||
hash.len = hasher->get_block_size(hasher);
|
||||
hash.ptr = alloca(hash.len);
|
||||
hasher->get_hash(hasher, pass, NULL);
|
||||
hasher->get_hash(hasher, *iv, hash.ptr);
|
||||
|
||||
memcpy(key.ptr, hash.ptr, hash.len);
|
||||
|
||||
hasher->get_hash(hasher, hash, NULL);
|
||||
hasher->get_hash(hasher, pass, NULL);
|
||||
hasher->get_hash(hasher, *iv, hash.ptr);
|
||||
|
||||
memcpy(key.ptr + hash.len, hash.ptr, key.len - hash.len);
|
||||
|
||||
hasher->destroy(hasher);
|
||||
|
||||
/* decrypt blob */
|
||||
crypter = crypter_create(ENCR_3DES, 0);
|
||||
crypter->set_key(crypter, key);
|
||||
crypter->decrypt(crypter, *blob, *iv, &decrypted);
|
||||
memcpy(blob->ptr, decrypted.ptr, blob->len);
|
||||
chunk_free(&decrypted);
|
||||
|
||||
/* determine amount of padding */
|
||||
last_padding_pos = blob->ptr + blob->len - 1;
|
||||
padding = *last_padding_pos;
|
||||
first_padding_pos = (padding > blob->len) ? blob->ptr : last_padding_pos - padding;
|
||||
|
||||
/* check the padding pattern */
|
||||
while (--last_padding_pos > first_padding_pos)
|
||||
{
|
||||
if (*last_padding_pos != padding)
|
||||
return FALSE;
|
||||
}
|
||||
/* remove padding */
|
||||
blob->len -= padding;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Converts a PEM encoded file into its binary form
|
||||
*
|
||||
* RFC 1421 Privacy Enhancement for Electronic Mail, February 1993
|
||||
* RFC 934 Message Encapsulation, January 1985
|
||||
*/
|
||||
status_t pemtobin(chunk_t *blob, char *pass)
|
||||
{
|
||||
typedef enum {
|
||||
PEM_PRE = 0,
|
||||
PEM_MSG = 1,
|
||||
PEM_HEADER = 2,
|
||||
PEM_BODY = 3,
|
||||
PEM_POST = 4,
|
||||
PEM_ABORT = 5
|
||||
} state_t;
|
||||
|
||||
bool encrypted = FALSE;
|
||||
|
||||
state_t state = PEM_PRE;
|
||||
|
||||
chunk_t src = *blob;
|
||||
chunk_t dst = *blob;
|
||||
chunk_t line = CHUNK_INITIALIZER;
|
||||
chunk_t iv = CHUNK_INITIALIZER;
|
||||
|
||||
u_char iv_buf[16]; /* MD5 digest size */
|
||||
|
||||
/* zero size of converted blob */
|
||||
dst.len = 0;
|
||||
|
||||
/* zero size of IV */
|
||||
iv.ptr = iv_buf;
|
||||
iv.len = 0;
|
||||
|
||||
while (fetchline(&src, &line))
|
||||
{
|
||||
if (state == PEM_PRE)
|
||||
{
|
||||
if (find_boundary("BEGIN", &line))
|
||||
{
|
||||
state = PEM_MSG;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (find_boundary("END", &line))
|
||||
{
|
||||
state = PEM_POST;
|
||||
break;
|
||||
}
|
||||
if (state == PEM_MSG)
|
||||
{
|
||||
state = (memchr(line.ptr, ':', line.len) == NULL) ? PEM_BODY : PEM_HEADER;
|
||||
}
|
||||
if (state == PEM_HEADER)
|
||||
{
|
||||
chunk_t name = CHUNK_INITIALIZER;
|
||||
chunk_t value = CHUNK_INITIALIZER;
|
||||
|
||||
/* an empty line separates HEADER and BODY */
|
||||
if (line.len == 0)
|
||||
{
|
||||
state = PEM_BODY;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* we are looking for a name: value pair */
|
||||
if (!extract_parameter(&name, &value, &line))
|
||||
continue;
|
||||
|
||||
if (match("Proc-Type", &name) && *value.ptr == '4')
|
||||
encrypted = TRUE;
|
||||
else if (match("DEK-Info", &name))
|
||||
{
|
||||
const char *ugh = NULL;
|
||||
size_t len = 0;
|
||||
chunk_t dek;
|
||||
|
||||
if (!extract_token(&dek, ',', &value))
|
||||
dek = value;
|
||||
|
||||
/* we support DES-EDE3-CBC encrypted files, only */
|
||||
if (!match("DES-EDE3-CBC", &dek))
|
||||
return NOT_SUPPORTED;
|
||||
|
||||
eat_whitespace(&value);
|
||||
ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len);
|
||||
if (ugh)
|
||||
return PARSE_ERROR;
|
||||
|
||||
iv.len = len;
|
||||
}
|
||||
}
|
||||
else /* state is PEM_BODY */
|
||||
{
|
||||
const char *ugh = NULL;
|
||||
size_t len = 0;
|
||||
chunk_t data;
|
||||
|
||||
/* remove any trailing whitespace */
|
||||
if (!extract_token(&data ,' ', &line))
|
||||
{
|
||||
data = line;
|
||||
}
|
||||
|
||||
ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len);
|
||||
if (ugh)
|
||||
{
|
||||
state = PEM_ABORT;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.ptr += len;
|
||||
dst.len += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set length to size of binary blob */
|
||||
blob->len = dst.len;
|
||||
|
||||
if (state != PEM_POST)
|
||||
return PARSE_ERROR;
|
||||
|
||||
if (encrypted)
|
||||
return pem_decrypt(blob, &iv, pass);
|
||||
else
|
||||
return SUCCESS;
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Martin Willi
|
||||
* Hochschule fuer Technik Rapperswil
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef PEM_H_
|
||||
#define PEM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <types.h>
|
||||
|
||||
status_t pemtobin(chunk_t *blob, char *pass);
|
||||
|
||||
#endif /*PEM_H_*/
|
||||
@@ -0,0 +1,723 @@
|
||||
/*
|
||||
* convert from text form of arbitrary data (e.g., keys) to binary
|
||||
* Copyright (C) 2000 Henry Spencer.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#include "ttodata.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* converters and misc */
|
||||
static int unhex(const char *, char *, size_t);
|
||||
static int unb64(const char *, char *, size_t);
|
||||
static int untext(const char *, char *, size_t);
|
||||
static const char *badch(const char *, int, char *, size_t);
|
||||
|
||||
/* internal error codes for converters */
|
||||
#define SHORT (-2) /* internal buffer too short */
|
||||
#define BADPAD (-3) /* bad base64 padding */
|
||||
#define BADCH0 (-4) /* invalid character 0 */
|
||||
#define BADCH1 (-5) /* invalid character 1 */
|
||||
#define BADCH2 (-6) /* invalid character 2 */
|
||||
#define BADCH3 (-7) /* invalid character 3 */
|
||||
#define BADOFF(code) (BADCH0-(code))
|
||||
|
||||
/*
|
||||
- ttodatav - convert text to data, with verbose error reports
|
||||
* If some of this looks slightly odd, it's because it has changed
|
||||
* repeatedly (from the original atodata()) without a major rewrite.
|
||||
*/
|
||||
const char * /* NULL on success, else literal or errp */
|
||||
ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags)
|
||||
const char *src;
|
||||
size_t srclen; /* 0 means apply strlen() */
|
||||
int base; /* 0 means figure it out */
|
||||
char *dst; /* need not be valid if dstlen is 0 */
|
||||
size_t dstlen;
|
||||
size_t *lenp; /* where to record length (NULL is nowhere) */
|
||||
char *errp; /* error buffer */
|
||||
size_t errlen;
|
||||
unsigned int flags;
|
||||
{
|
||||
size_t ingroup; /* number of input bytes converted at once */
|
||||
char buf[4]; /* output from conversion */
|
||||
int nbytes; /* size of output */
|
||||
int (*decode)(const char *, char *, size_t);
|
||||
char *stop;
|
||||
int ndone;
|
||||
int i;
|
||||
int underscoreok;
|
||||
int skipSpace = 0;
|
||||
|
||||
if (srclen == 0)
|
||||
srclen = strlen(src);
|
||||
if (dstlen == 0)
|
||||
dst = buf; /* point it somewhere valid */
|
||||
stop = dst + dstlen;
|
||||
|
||||
if (base == 0) {
|
||||
if (srclen < 2)
|
||||
return "input too short to be valid";
|
||||
if (*src++ != '0')
|
||||
return "input does not begin with format prefix";
|
||||
switch (*src++) {
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
base = 64;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
base = 256;
|
||||
break;
|
||||
default:
|
||||
return "unknown format prefix";
|
||||
}
|
||||
srclen -= 2;
|
||||
}
|
||||
switch (base) {
|
||||
case 16:
|
||||
decode = unhex;
|
||||
underscoreok = 1;
|
||||
ingroup = 2;
|
||||
break;
|
||||
case 64:
|
||||
decode = unb64;
|
||||
underscoreok = 0;
|
||||
ingroup = 4;
|
||||
if(flags & TTODATAV_IGNORESPACE) {
|
||||
skipSpace = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 256:
|
||||
decode = untext;
|
||||
ingroup = 1;
|
||||
underscoreok = 0;
|
||||
break;
|
||||
default:
|
||||
return "unknown base";
|
||||
}
|
||||
|
||||
/* proceed */
|
||||
ndone = 0;
|
||||
while (srclen > 0) {
|
||||
char stage[4]; /* staging area for group */
|
||||
size_t sl = 0;
|
||||
|
||||
/* Grab ingroup characters into stage,
|
||||
* squeezing out blanks if we are supposed to ignore them.
|
||||
*/
|
||||
for (sl = 0; sl < ingroup; src++, srclen--) {
|
||||
if (srclen == 0)
|
||||
return "input ends in mid-byte, perhaps truncated";
|
||||
else if (!(skipSpace && (*src == ' ' || *src == '\t')))
|
||||
stage[sl++] = *src;
|
||||
}
|
||||
|
||||
nbytes = (*decode)(stage, buf, sizeof(buf));
|
||||
switch (nbytes) {
|
||||
case BADCH0:
|
||||
case BADCH1:
|
||||
case BADCH2:
|
||||
case BADCH3:
|
||||
return badch(stage, nbytes, errp, errlen);
|
||||
case SHORT:
|
||||
return "internal buffer too short (\"can't happen\")";
|
||||
case BADPAD:
|
||||
return "bad (non-zero) padding at end of base64 input";
|
||||
}
|
||||
if (nbytes <= 0)
|
||||
return "unknown internal error";
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
if (dst < stop)
|
||||
*dst++ = buf[i];
|
||||
ndone++;
|
||||
}
|
||||
while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){
|
||||
src++;
|
||||
srclen--;
|
||||
}
|
||||
if (underscoreok && srclen > 1 && *src == '_') {
|
||||
/* srclen > 1 means not last character */
|
||||
src++;
|
||||
srclen--;
|
||||
}
|
||||
}
|
||||
|
||||
if (ndone == 0)
|
||||
return "no data bytes specified by input";
|
||||
if (lenp != NULL)
|
||||
*lenp = ndone;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
- ttodata - convert text to data
|
||||
*/
|
||||
const char * /* NULL on success, else literal */
|
||||
ttodata(src, srclen, base, dst, dstlen, lenp)
|
||||
const char *src;
|
||||
size_t srclen; /* 0 means apply strlen() */
|
||||
int base; /* 0 means figure it out */
|
||||
char *dst; /* need not be valid if dstlen is 0 */
|
||||
size_t dstlen;
|
||||
size_t *lenp; /* where to record length (NULL is nowhere) */
|
||||
{
|
||||
return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
|
||||
(size_t)0, TTODATAV_SPACECOUNTS);
|
||||
}
|
||||
|
||||
/*
|
||||
- atodata - convert ASCII to data
|
||||
* backward-compatibility interface
|
||||
*/
|
||||
size_t /* 0 for failure, true length for success */
|
||||
atodata(src, srclen, dst, dstlen)
|
||||
const char *src;
|
||||
size_t srclen;
|
||||
char *dst;
|
||||
size_t dstlen;
|
||||
{
|
||||
size_t len;
|
||||
const char *err;
|
||||
|
||||
err = ttodata(src, srclen, 0, dst, dstlen, &len);
|
||||
if (err != NULL)
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
- atobytes - convert ASCII to data bytes
|
||||
* another backward-compatibility interface
|
||||
*/
|
||||
const char *
|
||||
atobytes(src, srclen, dst, dstlen, lenp)
|
||||
const char *src;
|
||||
size_t srclen;
|
||||
char *dst;
|
||||
size_t dstlen;
|
||||
size_t *lenp;
|
||||
{
|
||||
return ttodata(src, srclen, 0, dst, dstlen, lenp);
|
||||
}
|
||||
|
||||
/*
|
||||
- unhex - convert two ASCII hex digits to byte
|
||||
*/
|
||||
static int /* number of result bytes, or error code */
|
||||
unhex(src, dst, dstlen)
|
||||
const char *src; /* known to be full length */
|
||||
char *dst;
|
||||
size_t dstlen; /* not large enough is a failure */
|
||||
{
|
||||
char *p;
|
||||
unsigned byte;
|
||||
static char hex[] = "0123456789abcdef";
|
||||
|
||||
if (dstlen < 1)
|
||||
return SHORT;
|
||||
|
||||
p = strchr(hex, *src);
|
||||
if (p == NULL)
|
||||
p = strchr(hex, tolower(*src));
|
||||
if (p == NULL)
|
||||
return BADCH0;
|
||||
byte = (p - hex) << 4;
|
||||
src++;
|
||||
|
||||
p = strchr(hex, *src);
|
||||
if (p == NULL)
|
||||
p = strchr(hex, tolower(*src));
|
||||
if (p == NULL)
|
||||
return BADCH1;
|
||||
byte |= (p - hex);
|
||||
|
||||
*dst = byte;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
- unb64 - convert four ASCII base64 digits to three bytes
|
||||
* Note that a base64 digit group is padded out with '=' if it represents
|
||||
* less than three bytes: one byte is dd==, two is ddd=, three is dddd.
|
||||
*/
|
||||
static int /* number of result bytes, or error code */
|
||||
unb64(src, dst, dstlen)
|
||||
const char *src; /* known to be full length */
|
||||
char *dst;
|
||||
size_t dstlen;
|
||||
{
|
||||
char *p;
|
||||
unsigned byte1;
|
||||
unsigned byte2;
|
||||
static char base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
if (dstlen < 3)
|
||||
return SHORT;
|
||||
|
||||
p = strchr(base64, *src++);
|
||||
|
||||
if (p == NULL)
|
||||
return BADCH0;
|
||||
byte1 = (p - base64) << 2; /* first six bits */
|
||||
|
||||
p = strchr(base64, *src++);
|
||||
if (p == NULL) {
|
||||
return BADCH1;
|
||||
}
|
||||
|
||||
byte2 = p - base64; /* next six: two plus four */
|
||||
*dst++ = byte1 | (byte2 >> 4);
|
||||
byte1 = (byte2 & 0xf) << 4;
|
||||
|
||||
p = strchr(base64, *src++);
|
||||
if (p == NULL) {
|
||||
if (*(src-1) == '=' && *src == '=') {
|
||||
if (byte1 != 0) /* bad padding */
|
||||
return BADPAD;
|
||||
return 1;
|
||||
}
|
||||
return BADCH2;
|
||||
}
|
||||
|
||||
byte2 = p - base64; /* next six: four plus two */
|
||||
*dst++ = byte1 | (byte2 >> 2);
|
||||
byte1 = (byte2 & 0x3) << 6;
|
||||
|
||||
p = strchr(base64, *src++);
|
||||
if (p == NULL) {
|
||||
if (*(src-1) == '=') {
|
||||
if (byte1 != 0) /* bad padding */
|
||||
return BADPAD;
|
||||
return 2;
|
||||
}
|
||||
return BADCH3;
|
||||
}
|
||||
byte2 = p - base64; /* last six */
|
||||
*dst++ = byte1 | byte2;
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*
|
||||
- untext - convert one ASCII character to byte
|
||||
*/
|
||||
static int /* number of result bytes, or error code */
|
||||
untext(src, dst, dstlen)
|
||||
const char *src; /* known to be full length */
|
||||
char *dst;
|
||||
size_t dstlen; /* not large enough is a failure */
|
||||
{
|
||||
if (dstlen < 1)
|
||||
return SHORT;
|
||||
|
||||
*dst = *src;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
- badch - produce a nice complaint about an unknown character
|
||||
*
|
||||
* If the compiler complains that the array bigenough[] has a negative
|
||||
* size, that means the TTODATAV_BUF constant has been set too small.
|
||||
*/
|
||||
static const char * /* literal or errp */
|
||||
badch(src, errcode, errp, errlen)
|
||||
const char *src;
|
||||
int errcode;
|
||||
char *errp; /* might be NULL */
|
||||
size_t errlen;
|
||||
{
|
||||
static const char pre[] = "unknown character (`";
|
||||
static const char suf[] = "') in input";
|
||||
char buf[5];
|
||||
# define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
|
||||
struct sizecheck {
|
||||
char bigenough[TTODATAV_BUF - REQD]; /* see above */
|
||||
};
|
||||
char ch;
|
||||
|
||||
if (errp == NULL || errlen < REQD)
|
||||
return "unknown character in input";
|
||||
strcpy(errp, pre);
|
||||
ch = *(src + BADOFF(errcode));
|
||||
if (isprint(ch)) {
|
||||
buf[0] = ch;
|
||||
buf[1] = '\0';
|
||||
} else {
|
||||
buf[0] = '\\';
|
||||
buf[1] = ((ch & 0700) >> 6) + '0';
|
||||
buf[2] = ((ch & 0070) >> 3) + '0';
|
||||
buf[3] = ((ch & 0007) >> 0) + '0';
|
||||
buf[4] = '\0';
|
||||
}
|
||||
strcat(errp, buf);
|
||||
strcat(errp, suf);
|
||||
return (const char *)errp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef TTODATA_MAIN
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct artab;
|
||||
static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status);
|
||||
static void regress(char *pgm);
|
||||
static void hexout(const char *s, size_t len, FILE *f);
|
||||
|
||||
/*
|
||||
- main - convert first argument to hex, or run regression
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char buf[1024];
|
||||
char buf2[1024];
|
||||
char err[512];
|
||||
size_t n;
|
||||
size_t i;
|
||||
char *p = buf;
|
||||
char *p2 = buf2;
|
||||
char *pgm = argv[0];
|
||||
const char *oops;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "-r") == 0) {
|
||||
regress(pgm); /* should not return */
|
||||
fprintf(stderr, "%s: regress() returned?!?\n", pgm);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n,
|
||||
err, sizeof(err), TTODATAV_IGNORESPACE);
|
||||
if (oops != NULL) {
|
||||
fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm,
|
||||
oops, argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (n > sizeof(buf)) {
|
||||
p = (char *)malloc((size_t)n);
|
||||
if (p == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: unable to malloc %d bytes for result\n",
|
||||
pgm, n);
|
||||
exit(1);
|
||||
}
|
||||
oops = ttodata(argv[1], 0, 0, p, n, &n);
|
||||
if (oops != NULL) {
|
||||
fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n",
|
||||
pgm, oops);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
hexout(p, n, stdout);
|
||||
printf("\n");
|
||||
|
||||
i = datatot(buf, n, 'h', buf2, sizeof(buf2));
|
||||
if (i == 0) {
|
||||
fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm,
|
||||
argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (i > sizeof(buf2)) {
|
||||
p2 = (char *)malloc((size_t)i);
|
||||
if (p == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: unable to malloc %d bytes for result\n",
|
||||
pgm, i);
|
||||
exit(1);
|
||||
}
|
||||
i = datatot(buf, n, 'h', p2, i);
|
||||
if (i == 0) {
|
||||
fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s\n", p2);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
- hexout - output an arbitrary-length string in hex
|
||||
*/
|
||||
static void
|
||||
hexout(s, len, f)
|
||||
const char *s;
|
||||
size_t len;
|
||||
FILE *f;
|
||||
{
|
||||
size_t i;
|
||||
|
||||
fprintf(f, "0x");
|
||||
for (i = 0; i < len; i++)
|
||||
fprintf(f, "%02x", (unsigned char)s[i]);
|
||||
}
|
||||
|
||||
struct artab {
|
||||
int base;
|
||||
# define IGNORESPACE_BIAS 1000
|
||||
char *ascii; /* NULL for end */
|
||||
char *data; /* NULL for error expected */
|
||||
} atodatatab[] = {
|
||||
{ 0, "", NULL, },
|
||||
{ 0, "0", NULL, },
|
||||
{ 0, "0x", NULL, },
|
||||
{ 0, "0xa", NULL, },
|
||||
{ 0, "0xab", "\xab", },
|
||||
{ 0, "0xabc", NULL, },
|
||||
{ 0, "0xabcd", "\xab\xcd", },
|
||||
{ 0, "0x0123456789", "\x01\x23\x45\x67\x89", },
|
||||
{ 0, "0x01x", NULL, },
|
||||
{ 0, "0xabcdef", "\xab\xcd\xef", },
|
||||
{ 0, "0xABCDEF", "\xab\xcd\xef", },
|
||||
{ 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", },
|
||||
{ 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", },
|
||||
{ 0, "0XaBc0_", NULL, },
|
||||
{ 0, "0X_aBc0", NULL, },
|
||||
{ 0, "0Xa_Bc0", NULL, },
|
||||
{ 16, "aBc0eEd8", "\xab\xc0\xee\xd8", },
|
||||
{ 0, "0s", NULL, },
|
||||
{ 0, "0sA", NULL, },
|
||||
{ 0, "0sBA", NULL, },
|
||||
{ 0, "0sCBA", NULL, },
|
||||
{ 0, "0sDCBA", "\x0c\x20\x40", },
|
||||
{ 0, "0SDCBA", "\x0c\x20\x40", },
|
||||
{ 0, "0sDA==", "\x0c", },
|
||||
{ 0, "0sDC==", NULL, },
|
||||
{ 0, "0sDCA=", "\x0c\x20", },
|
||||
{ 0, "0sDCB=", NULL, },
|
||||
{ 0, "0sDCAZ", "\x0c\x20\x19", },
|
||||
{ 0, "0sDCAa", "\x0c\x20\x1a", },
|
||||
{ 0, "0sDCAz", "\x0c\x20\x33", },
|
||||
{ 0, "0sDCA0", "\x0c\x20\x34", },
|
||||
{ 0, "0sDCA9", "\x0c\x20\x3d", },
|
||||
{ 0, "0sDCA+", "\x0c\x20\x3e", },
|
||||
{ 0, "0sDCA/", "\x0c\x20\x3f", },
|
||||
{ 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
|
||||
{ 0, "0t", NULL, },
|
||||
{ 0, "0tabc_xyz", "abc_xyz", },
|
||||
{ 256, "abc_xyz", "abc_xyz", },
|
||||
{ 0, NULL, NULL, },
|
||||
};
|
||||
|
||||
struct drtab {
|
||||
char *data; /* input; NULL for end */
|
||||
char format;
|
||||
int buflen; /* -1 means big buffer */
|
||||
int outlen; /* -1 means strlen(ascii)+1 */
|
||||
char *ascii; /* NULL for error expected */
|
||||
} datatoatab[] = {
|
||||
{ "", 'x', -1, -1, NULL, },
|
||||
{ "", 'X', -1, -1, NULL, },
|
||||
{ "", 'n', -1, -1, NULL, },
|
||||
{ "0", 'x', -1, -1, "0x30", },
|
||||
{ "0", 'x', 0, 5, "---", },
|
||||
{ "0", 'x', 1, 5, "", },
|
||||
{ "0", 'x', 2, 5, "0", },
|
||||
{ "0", 'x', 3, 5, "0x", },
|
||||
{ "0", 'x', 4, 5, "0x3", },
|
||||
{ "0", 'x', 5, 5, "0x30", },
|
||||
{ "0", 'x', 6, 5, "0x30", },
|
||||
{ "\xab\xcd", 'x', -1, -1, "0xabcd", },
|
||||
{ "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", },
|
||||
{ "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", },
|
||||
{ "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", },
|
||||
{ "\x01\x02", 'h', -1, -1, "0x0102", },
|
||||
{ "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", },
|
||||
{ "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", },
|
||||
{ "\x0c\x20\x40", 's', -1, -1, "0sDCBA", },
|
||||
{ "\x0c\x20\x40", 's', 0, 7, "---", },
|
||||
{ "\x0c\x20\x40", 's', 1, 7, "", },
|
||||
{ "\x0c\x20\x40", 's', 2, 7, "0", },
|
||||
{ "\x0c\x20\x40", 's', 3, 7, "0s", },
|
||||
{ "\x0c\x20\x40", 's', 4, 7, "0sD", },
|
||||
{ "\x0c\x20\x40", 's', 5, 7, "0sDC", },
|
||||
{ "\x0c\x20\x40", 's', 6, 7, "0sDCB", },
|
||||
{ "\x0c\x20\x40", 's', 7, 7, "0sDCBA", },
|
||||
{ "\x0c\x20\x40", 's', 8, 7, "0sDCBA", },
|
||||
{ "\x0c", 's', -1, -1, "0sDA==", },
|
||||
{ "\x0c\x20", 's', -1, -1, "0sDCA=", },
|
||||
{ "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", },
|
||||
{ "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", },
|
||||
{ "\x0c\x20\x33", 's', -1, -1, "0sDCAz", },
|
||||
{ "\x0c\x20\x34", 's', -1, -1, "0sDCA0", },
|
||||
{ "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", },
|
||||
{ "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", },
|
||||
{ "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", },
|
||||
{ "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", },
|
||||
{ "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", },
|
||||
{ NULL, 'x', -1, -1, NULL, },
|
||||
};
|
||||
|
||||
/*
|
||||
- regress - regression-test ttodata() and datatot()
|
||||
*/
|
||||
static void
|
||||
check(r, buf, n, oops, status)
|
||||
struct artab *r;
|
||||
char *buf;
|
||||
size_t n;
|
||||
err_t oops;
|
||||
int *status;
|
||||
{
|
||||
if (oops != NULL && r->data == NULL)
|
||||
{} /* error expected */
|
||||
else if (oops != NULL) {
|
||||
printf("`%s' gave error `%s', expecting %d `", r->ascii,
|
||||
oops, strlen(r->data));
|
||||
hexout(r->data, strlen(r->data), stdout);
|
||||
printf("'\n");
|
||||
*status = 1;
|
||||
} else if (r->data == NULL) {
|
||||
printf("`%s' gave %d `", r->ascii, n);
|
||||
hexout(buf, n, stdout);
|
||||
printf("', expecting error\n");
|
||||
*status = 1;
|
||||
} else if (n != strlen(r->data)) {
|
||||
printf("length wrong in `%s': got %d `", r->ascii, n);
|
||||
hexout(buf, n, stdout);
|
||||
printf("', expecting %d `", strlen(r->data));
|
||||
hexout(r->data, strlen(r->data), stdout);
|
||||
printf("'\n");
|
||||
*status = 1;
|
||||
} else if (memcmp(buf, r->data, n) != 0) {
|
||||
printf("`%s' gave %d `", r->ascii, n);
|
||||
hexout(buf, n, stdout);
|
||||
printf("', expecting %d `", strlen(r->data));
|
||||
hexout(r->data, strlen(r->data), stdout);
|
||||
printf("'\n");
|
||||
*status = 1;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void /* should not return at all, in fact */
|
||||
regress(pgm)
|
||||
char *pgm;
|
||||
{
|
||||
struct artab *r;
|
||||
struct drtab *dr;
|
||||
char buf[100];
|
||||
size_t n;
|
||||
int status = 0;
|
||||
|
||||
for (r = atodatatab; r->ascii != NULL; r++) {
|
||||
int base = r->base;
|
||||
int xbase = 0;
|
||||
|
||||
if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') {
|
||||
switch (r->ascii[1]) {
|
||||
case 'x':
|
||||
case 'X':
|
||||
xbase = 16;
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
xbase = 64;
|
||||
break;
|
||||
case 't':
|
||||
case 'T':
|
||||
xbase = 256;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (base >= IGNORESPACE_BIAS) {
|
||||
base = base - IGNORESPACE_BIAS;
|
||||
check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
|
||||
if (xbase != 0)
|
||||
check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
|
||||
} else {
|
||||
check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status);
|
||||
if (base == 64 || xbase == 64)
|
||||
check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
|
||||
if (xbase != 0) {
|
||||
check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status);
|
||||
if (base == 64 || xbase == 64)
|
||||
check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (dr = datatoatab; dr->data != NULL; dr++) {
|
||||
size_t should;
|
||||
|
||||
strcpy(buf, "---");
|
||||
n = datatot(dr->data, strlen(dr->data), dr->format, buf,
|
||||
(dr->buflen == -1) ? sizeof(buf) : dr->buflen);
|
||||
should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1;
|
||||
if (dr->outlen != -1)
|
||||
should = dr->outlen;
|
||||
if (n == 0 && dr->ascii == NULL)
|
||||
{} /* error expected */
|
||||
else if (n == 0) {
|
||||
printf("`");
|
||||
hexout(dr->data, strlen(dr->data), stdout);
|
||||
printf("' %c gave error, expecting %d `%s'\n",
|
||||
dr->format, should, dr->ascii);
|
||||
status = 1;
|
||||
} else if (dr->ascii == NULL) {
|
||||
printf("`");
|
||||
hexout(dr->data, strlen(dr->data), stdout);
|
||||
printf("' %c gave %d `%.*s', expecting error\n",
|
||||
dr->format, n, (int)n, buf);
|
||||
status = 1;
|
||||
} else if (n != should) {
|
||||
printf("length wrong in `");
|
||||
hexout(dr->data, strlen(dr->data), stdout);
|
||||
printf("': got %d `%s'", n, buf);
|
||||
printf(", expecting %d `%s'\n", should, dr->ascii);
|
||||
status = 1;
|
||||
} else if (strcmp(buf, dr->ascii) != 0) {
|
||||
printf("`");
|
||||
hexout(dr->data, strlen(dr->data), stdout);
|
||||
printf("' gave %d `%s'", n, buf);
|
||||
printf(", expecting %d `%s'\n", should, dr->ascii);
|
||||
status = 1;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
exit(status);
|
||||
}
|
||||
|
||||
#endif /* TTODATA_MAIN */
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* convert from text form of arbitrary data (e.g., keys) to binary
|
||||
* Copyright (C) 2000 Henry Spencer.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Library General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
|
||||
* License for more details.
|
||||
*/
|
||||
|
||||
#ifndef TTODATA_H_
|
||||
#define TTODATA_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#define TTODATAV_BUF 40 /* ttodatav's largest non-literal message */
|
||||
#define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/
|
||||
#define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */
|
||||
|
||||
typedef const char *err_t; /* error message, or NULL for success */
|
||||
|
||||
err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed);
|
||||
|
||||
|
||||
#endif /* TTODATA_H_ */
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "rsa_private_key.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <asn1/der_decoder.h>
|
||||
#include <asn1-pluto/asn1-pluto.h>
|
||||
|
||||
|
||||
/*
|
||||
@@ -138,6 +138,8 @@ struct private_rsa_private_key_t {
|
||||
|
||||
};
|
||||
|
||||
#if 0
|
||||
Not used yet, since we use plutos ASN1 stuff
|
||||
/**
|
||||
* Rules for de-/encoding of a private key from/in ASN1
|
||||
*/
|
||||
@@ -154,6 +156,51 @@ static asn1_rule_t rsa_private_key_rules[] = {
|
||||
{ ASN1_INTEGER, ASN1_MPZ, offsetof(private_rsa_private_key_t, coeff), 0},
|
||||
{ASN1_END, 0, 0, 0},
|
||||
};
|
||||
#endif
|
||||
|
||||
struct {
|
||||
const char *name;
|
||||
size_t offset;
|
||||
} RSA_private_field[] = {
|
||||
{ "Modulus", offsetof(private_rsa_private_key_t, n) },
|
||||
{ "PublicExponent", offsetof(private_rsa_private_key_t, e) },
|
||||
{ "PrivateExponent", offsetof(private_rsa_private_key_t, d) },
|
||||
{ "Prime1", offsetof(private_rsa_private_key_t, p) },
|
||||
{ "Prime2", offsetof(private_rsa_private_key_t, q) },
|
||||
{ "Exponent1", offsetof(private_rsa_private_key_t, exp1) },
|
||||
{ "Exponent2", offsetof(private_rsa_private_key_t, exp2) },
|
||||
{ "Coefficient", offsetof(private_rsa_private_key_t, coeff) },
|
||||
};
|
||||
|
||||
/* ASN.1 definition of a PKCS#1 RSA private key */
|
||||
|
||||
static const asn1Object_t privkeyObjects[] = {
|
||||
{ 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
|
||||
{ 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
|
||||
{ 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
|
||||
{ 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
|
||||
{ 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
|
||||
{ 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
|
||||
{ 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
|
||||
{ 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
|
||||
{ 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 10 */
|
||||
{ 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
|
||||
{ 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
|
||||
{ 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
|
||||
{ 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
|
||||
{ 1, "end opt or loop", ASN1_EOC, ASN1_END } /* 15 */
|
||||
};
|
||||
|
||||
#define PKCS1_PRIV_KEY_VERSION 1
|
||||
#define PKCS1_PRIV_KEY_MODULUS 2
|
||||
#define PKCS1_PRIV_KEY_PUB_EXP 3
|
||||
#define PKCS1_PRIV_KEY_COEFF 9
|
||||
#define PKCS1_PRIV_KEY_ROOF 16
|
||||
|
||||
|
||||
|
||||
static private_rsa_private_key_t *rsa_private_key_create_empty();
|
||||
|
||||
@@ -548,6 +595,9 @@ rsa_private_key_t *rsa_private_key_create(size_t key_size)
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
NOT used yet, since we use plutos ASN1 parser for now
|
||||
/*
|
||||
* see header
|
||||
*/
|
||||
@@ -579,6 +629,152 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t chunk)
|
||||
this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
|
||||
return &this->public;
|
||||
}
|
||||
#endif
|
||||
|
||||
static status_t check(private_rsa_private_key_t *this)
|
||||
{
|
||||
mpz_t t, u, q1;
|
||||
status_t status = SUCCESS;
|
||||
|
||||
/* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets.
|
||||
* We actually require more (for security).
|
||||
*/
|
||||
if (this->k < 512/8)
|
||||
return FAILED;
|
||||
|
||||
/* we picked a max modulus size to simplify buffer allocation */
|
||||
if (this->k > 8192/8)
|
||||
return FAILED;
|
||||
|
||||
mpz_init(t);
|
||||
mpz_init(u);
|
||||
mpz_init(q1);
|
||||
|
||||
/* check that n == p * q */
|
||||
mpz_mul(u, this->p, this->q);
|
||||
if (mpz_cmp(u, this->n) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that e divides neither p-1 nor q-1 */
|
||||
mpz_sub_ui(t, this->p, 1);
|
||||
mpz_mod(t, t, this->e);
|
||||
if (mpz_cmp_ui(t, 0) == 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
mpz_sub_ui(t, this->q, 1);
|
||||
mpz_mod(t, t, this->e);
|
||||
if (mpz_cmp_ui(t, 0) == 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that d is e^-1 (mod lcm(p-1, q-1)) */
|
||||
/* see PKCS#1v2, aka RFC 2437, for the "lcm" */
|
||||
mpz_sub_ui(q1, this->q, 1);
|
||||
mpz_sub_ui(u, this->p, 1);
|
||||
mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */
|
||||
mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */
|
||||
mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */
|
||||
|
||||
mpz_mul(t, this->d, this->e);
|
||||
mpz_mod(t, t, u);
|
||||
if (mpz_cmp_ui(t, 1) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that exp1 is d mod (p-1) */
|
||||
mpz_sub_ui(u, this->p, 1);
|
||||
mpz_mod(t, this->d, u);
|
||||
if (mpz_cmp(t, this->exp1) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that exp2 is d mod (q-1) */
|
||||
mpz_sub_ui(u, this->q, 1);
|
||||
mpz_mod(t, this->d, u);
|
||||
if (mpz_cmp(t, this->exp2) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
/* check that coeff is (q^-1) mod p */
|
||||
mpz_mul(t, this->coeff, this->q);
|
||||
mpz_mod(t, t, this->p);
|
||||
if (mpz_cmp_ui(t, 1) != 0)
|
||||
{
|
||||
status = FAILED;
|
||||
}
|
||||
|
||||
mpz_clear(t);
|
||||
mpz_clear(u);
|
||||
mpz_clear(q1);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses a PKCS#1 private key
|
||||
*/
|
||||
rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
private_rsa_private_key_t *this;
|
||||
|
||||
this = rsa_private_key_create_empty();
|
||||
|
||||
mpz_init(this->n);
|
||||
mpz_init(this->e);
|
||||
mpz_init(this->p);
|
||||
mpz_init(this->q);
|
||||
mpz_init(this->d);
|
||||
mpz_init(this->exp1);
|
||||
mpz_init(this->exp2);
|
||||
mpz_init(this->coeff);
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE);
|
||||
|
||||
while (objectID < PKCS1_PRIV_KEY_ROOF)
|
||||
{
|
||||
if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (objectID == PKCS1_PRIV_KEY_VERSION)
|
||||
{
|
||||
if (object.len > 0 && *object.ptr != 0)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
|
||||
objectID <= PKCS1_PRIV_KEY_COEFF)
|
||||
{
|
||||
mpz_t *u = (mpz_t *) ((char *)this
|
||||
+ RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
|
||||
|
||||
mpz_import(*u, object.len, 1, 1, 1, 0, object.ptr);
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
if (check(this) != SUCCESS)
|
||||
{
|
||||
destroy(this);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return &this->public;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* see header
|
||||
|
||||
@@ -145,6 +145,11 @@ struct chunk_t {
|
||||
*/
|
||||
extern chunk_t CHUNK_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initialize a chunk to a static buffer
|
||||
*/
|
||||
#define chunk_from_buf(str) { str, sizeof(str) }
|
||||
|
||||
/**
|
||||
* Clone chunk contents in a newly allocated chunk
|
||||
*/
|
||||
|
||||
@@ -220,11 +220,11 @@ static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label,
|
||||
buffer_pos = buffer;
|
||||
if (this->output == NULL)
|
||||
{
|
||||
syslog(LOG_INFO, "[=>] [%5d ] %s %s", line_start, buffer, ascii_buffer);
|
||||
syslog(LOG_INFO, "[=>] [%5d] %s %s", line_start, buffer, ascii_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(this->output, "[=>] [%5d ] %s %s\n", line_start, buffer, ascii_buffer);
|
||||
fprintf(this->output, "[=>] [%5d] %s %s\n", line_start, buffer, ascii_buffer);
|
||||
}
|
||||
memset(ascii_buffer, 0, 16);
|
||||
line_start += 16;
|
||||
@@ -257,11 +257,11 @@ static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label,
|
||||
buffer_pos = buffer;
|
||||
if (this->output == NULL)
|
||||
{
|
||||
syslog(LOG_INFO, "[=>] [%5d ] %s %16s", line_start, buffer, ascii_buffer);
|
||||
syslog(LOG_INFO, "[=>] [%5d] %s %16s", line_start, buffer, ascii_buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(this->output, "[=>] [%5d ] %s %16s\n", line_start, buffer, ascii_buffer);
|
||||
fprintf(this->output, "[=>] [%5d] %s %16s\n", line_start, buffer, ascii_buffer);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
@@ -50,6 +50,7 @@ mapping_t logger_context_t_mappings[] = {
|
||||
{PAYLOAD, "PAYLOAD"},
|
||||
{DER_DECODER, "DER_DECODER"},
|
||||
{DER_ENCODER, "DER_ENCODER"},
|
||||
{ASN1, "ASN1"},
|
||||
{MAPPING_END, NULL},
|
||||
};
|
||||
|
||||
@@ -77,6 +78,7 @@ struct {
|
||||
{ "PAYLD", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* PAYLOAD */
|
||||
{ "DERDC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* DER_DECODER */
|
||||
{ "DEREC", ERROR|CONTROL|AUDIT|LEVEL0, TRUE }, /* DER_ENCODER */
|
||||
{ "ASN_1", ERROR|CONTROL|AUDIT|RAW|LEVEL3, TRUE }, /* ASN1 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ enum logger_context_t {
|
||||
PAYLOAD,
|
||||
DER_DECODER,
|
||||
DER_ENCODER,
|
||||
ASN1,
|
||||
LOGGER_CONTEXT_ROOF,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user