- using asn1 pluto stuff now

This commit is contained in:
Martin Willi
2006-04-18 07:22:20 +00:00
parent 1ab689ee60
commit 1d025fbcea
14 changed files with 92 additions and 21 deletions
+29
View File
@@ -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 $@ $<
+739
View File
@@ -0,0 +1,739 @@
/* 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;
}
/*
* codes ASN.1 lengths up to a size of 16'777'215 bytes
*/
void code_asn1_length(size_t length, chunk_t *code)
{
if (length < 128)
{
code->ptr[0] = length;
code->len = 1;
}
else if (length < 256)
{
code->ptr[0] = 0x81;
code->ptr[1] = (u_char) length;
code->len = 2;
}
else if (length < 65536)
{
code->ptr[0] = 0x82;
code->ptr[1] = length >> 8;
code->ptr[2] = length & 0x00ff;
code->len = 3;
}
else
{
code->ptr[0] = 0x83;
code->ptr[1] = length >> 16;
code->ptr[2] = (length >> 8) & 0x00ff;
code->ptr[3] = length & 0x0000ff;
code->len = 4;
}
}
/*
* build an empty asn.1 object with tag and length fields already filled in
*/
u_char* build_asn1_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 */
code_asn1_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);
pos += length.len;
return pos;
}
/*
* build a simple ASN.1 object
*/
chunk_t asn1_simple_object(asn1_t tag, chunk_t content)
{
chunk_t object;
u_char *pos = build_asn1_object(&object, tag, content.len);
memcpy(pos, content.ptr, content.len);
pos += content.len;
return object;
}
/* Build an ASN.1 object from a variable number of individual chunks.
* Depending on the mode, chunks either are moved ('m') or copied ('c').
*/
chunk_t asn1_wrap(asn1_t type, const char *mode, ...)
{
chunk_t construct;
va_list chunks;
u_char *pos;
int i;
int count = strlen(mode);
/* sum up lengths of individual chunks */
va_start(chunks, mode);
construct.len = 0;
for (i = 0; i < count; i++)
{
chunk_t ch = va_arg(chunks, chunk_t);
construct.len += ch.len;
}
va_end(chunks);
/* allocate needed memory for construct */
pos = build_asn1_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);
switch (*mode++)
{
case 'm':
memcpy(pos, ch.ptr, ch.len);
pos += ch.len;
free(ch.ptr);
break;
case 'c':
default:
memcpy(pos, ch.ptr, ch.len);
pos += ch.len;
}
}
va_end(chunks);
return construct;
}
/*
* convert a MP integer into a DER coded ASN.1 object
*/
chunk_t asn1_integer_from_mpz(const mpz_t value)
{
size_t bits = mpz_sizeinbase(value, 2); /* size in bits */
chunk_t n;
n.len = 1 + bits / 8; /* size in bytes */
n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value);
return asn1_wrap(ASN1_INTEGER, "m", n);
}
/*
* convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
*/
chunk_t timetoasn1(const time_t *time, asn1_t type)
{
int offset;
const char *format;
char buf[TIMETOA_BUF];
chunk_t formatted_time;
struct tm *t = gmtime(time);
if (type == ASN1_GENERALIZEDTIME)
{
format = "%04d%02d%02d%02d%02d%02dZ";
offset = 1900;
}
else /* ASN1_UTCTIME */
{
format = "%02d%02d%02d%02d%02d%02dZ";
offset = (t->tm_year < 100)? 0 : -100;
}
sprintf(buf, 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);
return asn1_simple_object(type, formatted_time);
}
+137
View File
@@ -0,0 +1,137 @@
/* 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;
#define TIMETOA_BUF 30
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);
extern void code_asn1_length(size_t length, chunk_t *code);
extern u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen);
extern chunk_t asn1_integer_from_mpz(const mpz_t value);
extern chunk_t asn1_simple_object(asn1_t tag, chunk_t content);
extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...);
extern chunk_t timetoasn1(const time_t *time, asn1_t type);
#endif /* _ASN1_H */
+194
View File
@@ -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 */
};
+75
View File
@@ -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
+123
View File
@@ -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;
+181
View File
@@ -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"
+343
View File
@@ -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;
}
+25
View File
@@ -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_*/
+374
View File
@@ -0,0 +1,374 @@
/*
* 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;
}
+30
View File
@@ -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_ */