scepclient and pluto use asn1 from libstrongswan
This commit is contained in:
@@ -105,7 +105,8 @@ AM_CFLAGS = -rdynamic \
|
||||
-DIPSEC_PIDDIR=\"${piddir}\" \
|
||||
-DIPSEC_PLUGINDIR=\"${plugindir}\" \
|
||||
-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \
|
||||
-DRESOLV_CONF=\"${resolv_conf}\"
|
||||
-DRESOLV_CONF=\"${resolv_conf}\" \
|
||||
-Wformat=0
|
||||
charon_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lpthread -lm -ldl
|
||||
|
||||
EXTRA_DIST = config/proposal_keywords.txt
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${nm_CFLAGS}
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
AM_CFLAGS = -rdynamic -Wformat=0
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-nm.la
|
||||
libstrongswan_nm_la_SOURCES = \
|
||||
|
||||
@@ -4,7 +4,8 @@ INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon
|
||||
AM_CFLAGS = -rdynamic \
|
||||
-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \
|
||||
-DIPSEC_PLUGINDIR=\"${plugindir}\" \
|
||||
-DPLUGINS=\""${libstrongswan_plugins}\""
|
||||
-DPLUGINS=\""${libstrongswan_plugins}\"" \
|
||||
-Wformat=0
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-sql.la
|
||||
libstrongswan_sql_la_SOURCES = sql_plugin.h sql_plugin.c \
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon -I$(top_srcdir)/src/stroke
|
||||
|
||||
AM_CFLAGS = -rdynamic -DIPSEC_CONFDIR=\"${confdir}\" -DIPSEC_PIDDIR=\"${piddir}\"
|
||||
AM_CFLAGS = \
|
||||
-rdynamic -Wformat=0 \
|
||||
-DIPSEC_CONFDIR=\"${confdir}\" \
|
||||
-DIPSEC_PIDDIR=\"${piddir}\"
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-stroke.la
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
AM_CFLAGS = -rdynamic -Wformat=0
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-updown.la
|
||||
libstrongswan_updown_la_SOURCES = \
|
||||
|
||||
@@ -16,4 +16,6 @@ irdumm_LDADD = libdumm.la -lruby1.8
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} \
|
||||
-I/usr/lib/ruby/1.8/i486-linux/
|
||||
AM_CFLAGS = -D_FILE_OFFSET_BITS=64
|
||||
AM_CFLAGS = \
|
||||
-D_FILE_OFFSET_BITS=64 \
|
||||
-Wformat=0
|
||||
|
||||
@@ -63,6 +63,8 @@ enum.c enum.h \
|
||||
printf_hook.c printf_hook.h \
|
||||
settings.c settings.h \
|
||||
utils.c utils.h \
|
||||
asn1/asn1.c asn1/asn1.h \
|
||||
asn1/asn1_parser.c asn1/asn1_parser.h \
|
||||
asn1/oid.c asn1/oid.h \
|
||||
utils/enumerator.c utils/enumerator.h \
|
||||
utils/lexparser.c utils/lexparser.h \
|
||||
@@ -70,8 +72,10 @@ utils/linked_list.c utils/linked_list.h \
|
||||
utils/optionsfrom.c utils/optionsfrom.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
AM_CFLAGS = -DIPSEC_DIR=\"${ipsecdir}\" \
|
||||
-DIPSEC_PLUGINDIR=\"${plugindir}\"
|
||||
AM_CFLAGS = \
|
||||
-DIPSEC_DIR=\"${ipsecdir}\" \
|
||||
-DIPSEC_PLUGINDIR=\"${plugindir}\" \
|
||||
-Wformat=0
|
||||
|
||||
if USE_LEAK_DETECTIVE
|
||||
AM_CFLAGS += -DLEAK_DETECTIVE
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <utils.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "oid.h"
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <utils.h>
|
||||
#include <chunk.h>
|
||||
|
||||
/**
|
||||
* Definition of some primitive ASN1 types
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <utils.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "asn1.h"
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <library.h>
|
||||
#include <utils.h>
|
||||
#include <chunk.h>
|
||||
#include <asn1/asn1.h>
|
||||
|
||||
/**
|
||||
* Definition of ASN.1 flags
|
||||
|
||||
@@ -225,13 +225,13 @@ bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force
|
||||
{
|
||||
if (fwrite(chunk.ptr, sizeof(u_char), chunk.len, fd) == chunk.len)
|
||||
{
|
||||
DBG1(" written to %s file '%s' (%d bytes)",
|
||||
DBG1(" written %s file '%s' (%d bytes)",
|
||||
label, path, chunk.len);
|
||||
good = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(" writing to %s file '%s' failed: %s",
|
||||
DBG1(" writing %s file '%s' failed: %s",
|
||||
label, path, strerror(errno));
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/libstrongswan
|
||||
|
||||
AM_CFLAGS = -rdynamic
|
||||
AM_CFLAGS = -rdynamic -Wformat=0
|
||||
|
||||
plugin_LTLIBRARIES = libstrongswan-x509.la
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ AM_CFLAGS = \
|
||||
-DIPSEC_CONFDIR=\"${confdir}\" \
|
||||
-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \
|
||||
-DIPSEC_PLUGINDIR=\"${plugindir}\" \
|
||||
-DPLUGINS=\""${libstrongswan_plugins}\""
|
||||
-DPLUGINS=\""${libstrongswan_plugins}\"" \
|
||||
-Wformat=0
|
||||
openac_LDADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lgmp
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ ipsec_PROGRAMS = pluto _pluto_adns
|
||||
pluto_SOURCES = \
|
||||
ac.c ac.h \
|
||||
alg_info.c alg_info.h \
|
||||
asn1.c asn1.h \
|
||||
ca.c ca.h \
|
||||
certs.c certs.h \
|
||||
connections.c connections.h \
|
||||
@@ -87,7 +86,8 @@ AM_CFLAGS = \
|
||||
-DSHARED_SECRETS_FILE=\"${confdir}/ipsec.secrets\" \
|
||||
-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \
|
||||
-DKERNEL26_SUPPORT -DKERNEL26_HAS_KAME_DUPLICATES \
|
||||
-DPLUTO -DKLIPS -DDEBUG
|
||||
-DPLUTO -DKLIPS -DDEBUG \
|
||||
-Wformat=0
|
||||
|
||||
pluto_LDADD = \
|
||||
$(LIBSTRONGSWANDIR)/libstrongswan-lite.la \
|
||||
|
||||
+192
-213
@@ -25,10 +25,11 @@
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "asn1.h"
|
||||
#include <utils.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#include "ac.h"
|
||||
#include "x509.h"
|
||||
#include "crl.h"
|
||||
@@ -38,120 +39,125 @@
|
||||
#include "whack.h"
|
||||
#include "fetch.h"
|
||||
|
||||
/* chained list of X.509 attribute certificates */
|
||||
|
||||
/**
|
||||
* Chained list of X.509 attribute certificates
|
||||
*/
|
||||
static x509acert_t *x509acerts = NULL;
|
||||
|
||||
/* chained list of ietfAttributes */
|
||||
|
||||
/**
|
||||
* Chained list of ietfAttributes
|
||||
*/
|
||||
static ietfAttrList_t *ietfAttributes = NULL;
|
||||
|
||||
/* ASN.1 definition of ietfAttrSyntax */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of ietfAttrSyntax
|
||||
*/
|
||||
static const asn1Object_t ietfAttrSyntaxObjects[] =
|
||||
{
|
||||
{ 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_BODY }, /* 1 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||
{ 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
|
||||
{ 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 4 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
|
||||
{ 2, "oid", ASN1_OID, ASN1_OPT |
|
||||
ASN1_BODY }, /* 6 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 2, "string", ASN1_UTF8STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 8 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END } /* 10 */
|
||||
{ 0, "ietfAttrSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "policyAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_BODY }, /* 1 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||
{ 1, "values", ASN1_SEQUENCE, ASN1_LOOP }, /* 3 */
|
||||
{ 2, "octets", ASN1_OCTET_STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 4 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 5 */
|
||||
{ 2, "oid", ASN1_OID, ASN1_OPT |
|
||||
ASN1_BODY }, /* 6 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 2, "string", ASN1_UTF8STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 8 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define IETF_ATTR_OCTETS 4
|
||||
#define IETF_ATTR_OID 6
|
||||
#define IETF_ATTR_STRING 8
|
||||
#define IETF_ATTR_ROOF 11
|
||||
|
||||
/* ASN.1 definition of roleSyntax */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of roleSyntax
|
||||
*/
|
||||
static const asn1Object_t roleSyntaxObjects[] =
|
||||
{
|
||||
{ 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 1 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||
{ 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ } /* 3 */
|
||||
{ 0, "roleSyntax", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "roleAuthority", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 1 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */
|
||||
{ 1, "roleName", ASN1_CONTEXT_C_1, ASN1_OBJ }, /* 3 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define ROLE_ROOF 4
|
||||
|
||||
/* ASN.1 definition of an X509 attribute certificate */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of an X509 attribute certificate
|
||||
*/
|
||||
static const asn1Object_t acObjects[] =
|
||||
{
|
||||
{ 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "version", ASN1_INTEGER, ASN1_DEF |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
|
||||
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
|
||||
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
|
||||
{ 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 7 */
|
||||
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 10 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
|
||||
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
|
||||
{ 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13*/
|
||||
{ 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
|
||||
ASN1_BODY }, /* 14 */
|
||||
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 15*/
|
||||
{ 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
|
||||
{ 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
|
||||
{ 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 19 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
|
||||
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
|
||||
{ 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
|
||||
{ 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
|
||||
{ 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
|
||||
{ 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 25 */
|
||||
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
|
||||
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
|
||||
{ 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
|
||||
{ 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
|
||||
{ 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
|
||||
ASN1_BODY }, /* 31 */
|
||||
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
|
||||
{ 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
|
||||
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
|
||||
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
|
||||
{ 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
|
||||
{ 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
|
||||
{ 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
|
||||
{ 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
|
||||
{ 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
|
||||
{ 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
|
||||
{ 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
|
||||
{ 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
|
||||
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
|
||||
{ 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
|
||||
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
|
||||
{ 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
|
||||
{ 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 50 */
|
||||
{ 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
|
||||
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 54 */
|
||||
{ 0, "AttributeCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "AttributeCertificateInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "version", ASN1_INTEGER, ASN1_DEF |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 2, "holder", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
|
||||
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 4 */
|
||||
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 6 */
|
||||
{ 4, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 7 */
|
||||
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 8 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 3, "entityName", ASN1_CONTEXT_C_1, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 10 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 11 */
|
||||
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 12 */
|
||||
{ 4, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 13 */
|
||||
{ 4, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
|
||||
ASN1_BODY }, /* 14 */
|
||||
{ 4, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
|
||||
{ 4, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 16 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
|
||||
{ 2, "v2Form", ASN1_CONTEXT_C_0, ASN1_NONE }, /* 18 */
|
||||
{ 3, "issuerName", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 19 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
|
||||
{ 3, "baseCertificateID", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 21 */
|
||||
{ 4, "issuerSerial", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
|
||||
{ 5, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 23 */
|
||||
{ 5, "serial", ASN1_INTEGER, ASN1_BODY }, /* 24 */
|
||||
{ 5, "issuerUID", ASN1_BIT_STRING, ASN1_OPT |
|
||||
ASN1_BODY }, /* 25 */
|
||||
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
|
||||
{ 3, "objectDigestInfo", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 28 */
|
||||
{ 4, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 29 */
|
||||
{ 5, "digestedObjectType", ASN1_ENUMERATED, ASN1_BODY }, /* 30 */
|
||||
{ 5, "otherObjectTypeID", ASN1_OID, ASN1_OPT |
|
||||
ASN1_BODY }, /* 31 */
|
||||
{ 5, "end opt", ASN1_EOC, ASN1_END }, /* 32 */
|
||||
{ 5, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 33 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 34 */
|
||||
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 35 */
|
||||
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 36 */
|
||||
{ 2, "attrCertValidityPeriod", ASN1_SEQUENCE, ASN1_NONE }, /* 37 */
|
||||
{ 3, "notBeforeTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 38 */
|
||||
{ 3, "notAfterTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 39 */
|
||||
{ 2, "attributes", ASN1_SEQUENCE, ASN1_LOOP }, /* 40 */
|
||||
{ 3, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 41 */
|
||||
{ 4, "type", ASN1_OID, ASN1_BODY }, /* 42 */
|
||||
{ 4, "values", ASN1_SET, ASN1_LOOP }, /* 43 */
|
||||
{ 5, "value", ASN1_EOC, ASN1_RAW }, /* 44 */
|
||||
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 45 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 46 */
|
||||
{ 2, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 47 */
|
||||
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 48 */
|
||||
{ 4, "extnID", ASN1_OID, ASN1_BODY }, /* 49 */
|
||||
{ 4, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 50 */
|
||||
{ 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 51 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 52 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 53 */
|
||||
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 54 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define AC_OBJ_CERTIFICATE 0
|
||||
@@ -173,7 +179,6 @@ static const asn1Object_t acObjects[] =
|
||||
#define AC_OBJ_EXTN_VALUE 51
|
||||
#define AC_OBJ_ALGORITHM 53
|
||||
#define AC_OBJ_SIGNATURE 54
|
||||
#define AC_OBJ_ROOF 55
|
||||
|
||||
const x509acert_t empty_ac = {
|
||||
NULL , /* *next */
|
||||
@@ -208,11 +213,11 @@ const x509acert_t empty_ac = {
|
||||
};
|
||||
|
||||
|
||||
/* compare two ietfAttributes, returns zero if a equals b
|
||||
/**
|
||||
* compare two ietfAttributes, returns zero if a equals b
|
||||
* negative/positive if a is earlier/later in the alphabet than b
|
||||
*/
|
||||
static int
|
||||
cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b)
|
||||
static int cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b)
|
||||
{
|
||||
int cmp_len, len, cmp_value;
|
||||
|
||||
@@ -227,11 +232,10 @@ cmp_ietfAttr(ietfAttr_t *a,ietfAttr_t *b)
|
||||
return (cmp_value == 0)? cmp_len : cmp_value;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* add an ietfAttribute to the chained list
|
||||
*/
|
||||
static ietfAttr_t*
|
||||
add_ietfAttr(ietfAttr_t *attr)
|
||||
static ietfAttr_t* add_ietfAttr(ietfAttr_t *attr)
|
||||
{
|
||||
ietfAttrList_t **listp = &ietfAttributes;
|
||||
ietfAttrList_t *list = *listp;
|
||||
@@ -270,11 +274,10 @@ add_ietfAttr(ietfAttr_t *attr)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* decodes a comma separated list of group attributes
|
||||
*/
|
||||
void
|
||||
decode_groups(char *groups, ietfAttrList_t **listp)
|
||||
void decode_groups(char *groups, ietfAttrList_t **listp)
|
||||
{
|
||||
if (groups == NULL)
|
||||
return;
|
||||
@@ -316,15 +319,13 @@ decode_groups(char *groups, ietfAttrList_t **listp)
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
same_attribute(const ietfAttr_t *a, const ietfAttr_t *b)
|
||||
static bool same_attribute(const ietfAttr_t *a, const ietfAttr_t *b)
|
||||
{
|
||||
return (a->kind == b->kind && a->value.len == b->value.len
|
||||
&& memeq(a->value.ptr, b->value.ptr, b->value.len));
|
||||
}
|
||||
|
||||
bool
|
||||
group_membership(const ietfAttrList_t *peer_list
|
||||
bool group_membership(const ietfAttrList_t *peer_list
|
||||
, const char *conn
|
||||
, const ietfAttrList_t *conn_list)
|
||||
{
|
||||
@@ -359,9 +360,7 @@ group_membership(const ietfAttrList_t *peer_list
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
unshare_ietfAttrList(ietfAttrList_t **listp)
|
||||
void unshare_ietfAttrList(ietfAttrList_t **listp)
|
||||
{
|
||||
ietfAttrList_t *list = *listp;
|
||||
|
||||
@@ -378,26 +377,22 @@ unshare_ietfAttrList(ietfAttrList_t **listp)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* parses ietfAttrSyntax
|
||||
/**
|
||||
* Parses ietfAttrSyntax
|
||||
*/
|
||||
static ietfAttrList_t*
|
||||
parse_ietfAttrSyntax(chunk_t blob, int level0)
|
||||
static ietfAttrList_t* parse_ietfAttrSyntax(chunk_t blob, int level0)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
|
||||
ietfAttrList_t *list = NULL;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(ietfAttrSyntaxObjects, blob);
|
||||
parser->set_top_level(parser, level0);
|
||||
|
||||
while (objectID < IETF_ATTR_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(ietfAttrSyntaxObjects, &objectID, &object, &level, &ctx))
|
||||
return NULL;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case IETF_ATTR_OCTETS:
|
||||
@@ -419,59 +414,52 @@ parse_ietfAttrSyntax(chunk_t blob, int level0)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
parser->destroy(parser);
|
||||
return list;
|
||||
}
|
||||
/*
|
||||
* parses roleSyntax
|
||||
|
||||
/**
|
||||
* Parses roleSyntax
|
||||
*/
|
||||
static void
|
||||
parse_roleSyntax(chunk_t blob, int level0)
|
||||
static void parse_roleSyntax(chunk_t blob, int level0)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(roleSyntaxObjects, blob);
|
||||
parser->set_top_level(parser, level0);
|
||||
|
||||
while (objectID < ROLE_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(roleSyntaxObjects, &objectID, &object, &level, &ctx))
|
||||
return;
|
||||
|
||||
switch (objectID) {
|
||||
default:
|
||||
break;
|
||||
switch (objectID)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
parser->destroy(parser);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Parses an X.509 attribute certificate
|
||||
*/
|
||||
bool
|
||||
parse_ac(chunk_t blob, x509acert_t *ac)
|
||||
bool parse_ac(chunk_t blob, x509acert_t *ac)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
int type = OID_UNKNOWN;
|
||||
int extn_oid = OID_UNKNOWN;
|
||||
bool success = FALSE;
|
||||
bool critical;
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(acObjects, blob);
|
||||
|
||||
while (objectID < AC_OBJ_ROOF) {
|
||||
|
||||
if (!extract_object(acObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
/* those objects which will parsed further need the next higher level */
|
||||
level++;
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
u_int level = parser->get_level(parser)+1;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
@@ -490,7 +478,7 @@ parse_ac(chunk_t blob, x509acert_t *ac)
|
||||
{
|
||||
plog("v%d attribute certificates are not supported"
|
||||
, ac->version);
|
||||
return FALSE;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case AC_OBJ_HOLDER_ISSUER:
|
||||
@@ -506,16 +494,16 @@ parse_ac(chunk_t blob, x509acert_t *ac)
|
||||
ac->issuerName = get_directoryName(object, level, FALSE);
|
||||
break;
|
||||
case AC_OBJ_SIG_ALG:
|
||||
ac->sigAlg = parse_algorithmIdentifier(object, level, NULL);
|
||||
ac->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case AC_OBJ_SERIAL_NUMBER:
|
||||
ac->serialNumber = object;
|
||||
break;
|
||||
case AC_OBJ_NOT_BEFORE:
|
||||
ac->notBefore = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
ac->notBefore = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case AC_OBJ_NOT_AFTER:
|
||||
ac->notAfter = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
ac->notAfter = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case AC_OBJ_ATTRIBUTE_TYPE:
|
||||
type = asn1_known_oid(object);
|
||||
@@ -582,7 +570,7 @@ parse_ac(chunk_t blob, x509acert_t *ac)
|
||||
}
|
||||
break;
|
||||
case AC_OBJ_ALGORITHM:
|
||||
ac->algorithm = parse_algorithmIdentifier(object, level, NULL);
|
||||
ac->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case AC_OBJ_SIGNATURE:
|
||||
ac->signature = object;
|
||||
@@ -591,17 +579,19 @@ parse_ac(chunk_t blob, x509acert_t *ac)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
success = parser->success(parser);
|
||||
time(&ac->installed);
|
||||
return TRUE;
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* release an ietfAttribute, free it if count reaches zero
|
||||
/**
|
||||
* Release an ietfAttribute, free it if count reaches zero
|
||||
*/
|
||||
static void
|
||||
release_ietfAttr(ietfAttr_t* attr)
|
||||
static void release_ietfAttr(ietfAttr_t* attr)
|
||||
{
|
||||
if (--attr->count == 0)
|
||||
{
|
||||
@@ -621,11 +611,10 @@ release_ietfAttr(ietfAttr_t* attr)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* free an ietfAttrList
|
||||
/**
|
||||
* Free an ietfAttrList
|
||||
*/
|
||||
void
|
||||
free_ietfAttrList(ietfAttrList_t* list)
|
||||
void free_ietfAttrList(ietfAttrList_t* list)
|
||||
{
|
||||
while (list != NULL)
|
||||
{
|
||||
@@ -637,11 +626,10 @@ free_ietfAttrList(ietfAttrList_t* list)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* free a X.509 attribute certificate
|
||||
/**
|
||||
* Free a X.509 attribute certificate
|
||||
*/
|
||||
void
|
||||
free_acert(x509acert_t *ac)
|
||||
void free_acert(x509acert_t *ac)
|
||||
{
|
||||
if (ac != NULL)
|
||||
{
|
||||
@@ -652,32 +640,29 @@ free_acert(x509acert_t *ac)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* free first X.509 attribute certificate in the chained list
|
||||
/**
|
||||
* Free first X.509 attribute certificate in the chained list
|
||||
*/
|
||||
static void
|
||||
free_first_acert(void)
|
||||
static void free_first_acert(void)
|
||||
{
|
||||
x509acert_t *first = x509acerts;
|
||||
x509acerts = first->next;
|
||||
free_acert(first);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Free all attribute certificates in the chained list
|
||||
*/
|
||||
void
|
||||
free_acerts(void)
|
||||
{
|
||||
void free_acerts(void)
|
||||
{
|
||||
while (x509acerts != NULL)
|
||||
free_first_acert();
|
||||
}
|
||||
|
||||
/*
|
||||
* get a X.509 attribute certificate for a given holder
|
||||
/**
|
||||
* Get a X.509 attribute certificate for a given holder
|
||||
*/
|
||||
x509acert_t*
|
||||
get_x509acert(chunk_t issuer, chunk_t serial)
|
||||
x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial)
|
||||
{
|
||||
x509acert_t *ac = x509acerts;
|
||||
x509acert_t *prev_ac = NULL;
|
||||
@@ -702,11 +687,10 @@ get_x509acert(chunk_t issuer, chunk_t serial)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* add a X.509 attribute certificate to the chained list
|
||||
/**
|
||||
* Add a X.509 attribute certificate to the chained list
|
||||
*/
|
||||
static void
|
||||
add_acert(x509acert_t *ac)
|
||||
static void add_acert(x509acert_t *ac)
|
||||
{
|
||||
x509acert_t *old_ac = get_x509acert(ac->holderIssuer, ac->holderSerial);
|
||||
|
||||
@@ -736,11 +720,11 @@ add_acert(x509acert_t *ac)
|
||||
x509acerts = ac;
|
||||
}
|
||||
|
||||
/* verify the validity of an attribute certificate by
|
||||
/**
|
||||
* Verify the validity of an attribute certificate by
|
||||
* checking the notBefore and notAfter dates
|
||||
*/
|
||||
static err_t
|
||||
check_ac_validity(const x509acert_t *ac)
|
||||
static err_t check_ac_validity(const x509acert_t *ac)
|
||||
{
|
||||
time_t current_time;
|
||||
|
||||
@@ -759,11 +743,10 @@ check_ac_validity(const x509acert_t *ac)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* verifies a X.509 attribute certificate
|
||||
*/
|
||||
bool
|
||||
verify_x509acert(x509acert_t *ac, bool strict)
|
||||
bool verify_x509acert(x509acert_t *ac, bool strict)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
x509cert_t *aacert;
|
||||
@@ -815,11 +798,10 @@ verify_x509acert(x509acert_t *ac, bool strict)
|
||||
return verify_x509cert(aacert, strict, &valid_until);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Loads X.509 attribute certificates
|
||||
*/
|
||||
void
|
||||
load_acerts(void)
|
||||
void load_acerts(void)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
|
||||
@@ -862,11 +844,10 @@ load_acerts(void)
|
||||
ignore_result(chdir(save_dir));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* lists group attributes separated by commas on a single line
|
||||
*/
|
||||
void
|
||||
format_groups(const ietfAttrList_t *list, char *buf, int len)
|
||||
void format_groups(const ietfAttrList_t *list, char *buf, int len)
|
||||
{
|
||||
bool first_group = TRUE;
|
||||
|
||||
@@ -894,11 +875,10 @@ format_groups(const ietfAttrList_t *list, char *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* list all X.509 attribute certificates in the chained list
|
||||
*/
|
||||
void
|
||||
list_acerts(bool utc)
|
||||
void list_acerts(bool utc)
|
||||
{
|
||||
x509acert_t *ac = x509acerts;
|
||||
time_t now;
|
||||
@@ -967,11 +947,10 @@ list_acerts(bool utc)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* list all group attributes in alphabetical order
|
||||
*/
|
||||
void
|
||||
list_groups(bool utc)
|
||||
void list_groups(bool utc)
|
||||
{
|
||||
ietfAttrList_t *list = ietfAttributes;
|
||||
|
||||
|
||||
@@ -1,825 +0,0 @@
|
||||
/* Simple ASN.1 parser
|
||||
* Copyright (C) 2000-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.
|
||||
*
|
||||
* RCSID $Id$
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "mp_defs.h"
|
||||
#include "asn1.h"
|
||||
#include <asn1/oid.h>
|
||||
#include "log.h"
|
||||
|
||||
/* 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 definition of an algorithmIdentifier */
|
||||
|
||||
static const asn1Object_t algorithmIdentifierObjects[] = {
|
||||
{ 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
|
||||
{ 1, "parameters", ASN1_EOC, ASN1_OPT |
|
||||
ASN1_RAW }, /* 2 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
|
||||
};
|
||||
|
||||
#define ALGORITHM_ID_ALG 1
|
||||
#define ALGORITHM_ID_PARAMETERS 2
|
||||
#define ALGORITHM_ID_ROOF 4
|
||||
|
||||
/*
|
||||
* 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_empty;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
asn1_known_oid(chunk_t object)
|
||||
{
|
||||
int oid = 0;
|
||||
|
||||
while (object.len)
|
||||
{
|
||||
if (oid_names[oid].octet == *object.ptr)
|
||||
{
|
||||
if (--object.len == 0 || oid_names[oid].down == 0)
|
||||
{
|
||||
return oid; /* found terminal symbol */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a known OID index to an ASN.1 OID
|
||||
*/
|
||||
chunk_t
|
||||
asn1_build_known_oid(int n)
|
||||
{
|
||||
chunk_t oid;
|
||||
int i;
|
||||
|
||||
if (n < 0 || n >= OID_MAX)
|
||||
{
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
i = oid_names[n].level + 1;
|
||||
oid.ptr = malloc(2 + i);
|
||||
oid.len = i;
|
||||
oid.ptr[0] = ASN1_OID;
|
||||
oid.ptr[1] = i;
|
||||
|
||||
do
|
||||
{
|
||||
if (oid_names[n].level >= i)
|
||||
{
|
||||
n--;
|
||||
continue;
|
||||
}
|
||||
oid.ptr[--i + 2] = oid_names[n--].octet;
|
||||
}
|
||||
while (i > 0);
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("number of length octets is larger than ASN.1 object")
|
||||
)
|
||||
return ASN1_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
if (n > sizeof(len))
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
chunkcpy(pos, length);
|
||||
|
||||
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);
|
||||
chunkcpy(pos, content);
|
||||
|
||||
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':
|
||||
mv_chunk(&pos, ch);
|
||||
break;
|
||||
case 'c':
|
||||
default:
|
||||
chunkcpy(pos, ch);
|
||||
}
|
||||
}
|
||||
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 */
|
||||
size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */
|
||||
chunk_t n = mpz_to_n(value, size);
|
||||
|
||||
return asn1_wrap(ASN1_INTEGER, "m", n);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
#define TIME_MAX 0x7fffffff
|
||||
|
||||
/*
|
||||
* Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
|
||||
*/
|
||||
time_t
|
||||
asn1totime(const chunk_t *utctime, asn1_t type)
|
||||
{
|
||||
struct tm t;
|
||||
time_t tc, 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 */
|
||||
}
|
||||
|
||||
/* parse ASN.1 time string */
|
||||
{
|
||||
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;
|
||||
|
||||
/* convert to time_t */
|
||||
tc = mktime(&t);
|
||||
|
||||
/* if no conversion overflow occurred, compensate timezone */
|
||||
return (tc == -1) ? TIME_MAX : (tc - timezone - tz_offset);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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[BUF_LEN];
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initializes the internal context of the ASN.1 parser
|
||||
*/
|
||||
void
|
||||
asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0,
|
||||
bool implicit, u_int cond)
|
||||
{
|
||||
ctx->blobs[0] = blob;
|
||||
ctx->level0 = level0;
|
||||
ctx->implicit = implicit;
|
||||
ctx->cond = cond;
|
||||
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, u_int cond)
|
||||
{
|
||||
int oid;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ASN1_OID:
|
||||
oid = asn1_known_oid(object);
|
||||
if (oid != OID_UNKNOWN)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" '%s'",oid_names[oid].name);
|
||||
)
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ASN1_UTF8STRING:
|
||||
case ASN1_IA5STRING:
|
||||
case ASN1_PRINTABLESTRING:
|
||||
case ASN1_T61STRING:
|
||||
case ASN1_VISIBLESTRING:
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" '%.*s'", (int)object.len, object.ptr);
|
||||
)
|
||||
return;
|
||||
case ASN1_UTCTIME:
|
||||
case ASN1_GENERALIZEDTIME:
|
||||
DBG(DBG_PARSING,
|
||||
time_t time = asn1totime(&object, type);
|
||||
DBG_log(" '%T'", &time, TRUE);
|
||||
)
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
DBG(cond,
|
||||
DBG_dump_chunk("", 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_empty;
|
||||
|
||||
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 */
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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))
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
|
||||
*level, obj.name, obj.type, *start_ptr);
|
||||
DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr));
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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);
|
||||
DBG(ctx->cond,
|
||||
DBG_dump_chunk("", *object);
|
||||
)
|
||||
}
|
||||
else if (obj.flags & ASN1_BODY)
|
||||
{
|
||||
*object = *blob1;
|
||||
debug_asn1_simple_object(*object, obj.type, ctx->cond);
|
||||
}
|
||||
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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
|
||||
level, name);
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*object->ptr != type)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
|
||||
level, name);
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log("L%d - %s:", level, name);
|
||||
)
|
||||
debug_asn1_simple_object(*object, type, DBG_RAW);
|
||||
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, DBG_RAW);
|
||||
|
||||
while (objectID < ALGORITHM_ID_ROOF)
|
||||
{
|
||||
if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
|
||||
return alg;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case ALGORITHM_ID_ALG:
|
||||
alg = asn1_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)
|
||||
{
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" file content is not binary ASN.1");
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
len = asn1_length(&blob);
|
||||
|
||||
/* exact match */
|
||||
if (len == blob.len)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* some websites append a surplus newline character to the blob */
|
||||
if (len + 1 == blob.len && *(blob.ptr + len) == '\n')
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DBG(DBG_PARSING,
|
||||
DBG_log(" file size does not match ASN.1 coded length");
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/* Simple ASN.1 parser
|
||||
* Copyright (C) 2000-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.
|
||||
*
|
||||
* RCSID $Id$
|
||||
*/
|
||||
|
||||
#ifndef _ASN1_H
|
||||
#define _ASN1_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <gmp.h>
|
||||
|
||||
#include "defs.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 cond;
|
||||
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 asn1_known_oid(chunk_t object);
|
||||
extern chunk_t asn1_build_known_oid(int n);
|
||||
extern u_int asn1_length(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 bool is_printablestring(chunk_t str);
|
||||
extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
|
||||
extern chunk_t timetoasn1(const time_t *time, asn1_t type);
|
||||
extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob
|
||||
, u_int level0, bool implicit, u_int cond);
|
||||
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 */
|
||||
|
||||
+25
-31
@@ -21,10 +21,11 @@
|
||||
#include <freeswan.h>
|
||||
#include <ipsec_policy.h>
|
||||
|
||||
#include "asn1/asn1.h"
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "asn1.h"
|
||||
#include "id.h"
|
||||
#include "x509.h"
|
||||
#include "pgp.h"
|
||||
@@ -32,16 +33,15 @@
|
||||
#include "certs.h"
|
||||
#include "pkcs1.h"
|
||||
|
||||
/*
|
||||
/**
|
||||
* used for initializatin of certs
|
||||
*/
|
||||
const cert_t empty_cert = {CERT_NONE, {NULL}};
|
||||
|
||||
/*
|
||||
/**
|
||||
* extracts the certificate to be sent to the peer
|
||||
*/
|
||||
chunk_t
|
||||
get_mycert(cert_t cert)
|
||||
chunk_t get_mycert(cert_t cert)
|
||||
{
|
||||
switch (cert.type)
|
||||
{
|
||||
@@ -57,9 +57,8 @@ get_mycert(cert_t cert)
|
||||
/* load a coded key or certificate file with autodetection
|
||||
* of binary DER or base64 PEM ASN.1 formats and armored PGP format
|
||||
*/
|
||||
bool
|
||||
load_coded_file(const char *filename, prompt_pass_t *pass, const char *type
|
||||
, chunk_t *blob, bool *pgp)
|
||||
bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type,
|
||||
chunk_t *blob, bool *pgp)
|
||||
{
|
||||
err_t ugh = NULL;
|
||||
|
||||
@@ -121,18 +120,17 @@ load_coded_file(const char *filename, prompt_pass_t *pass, const char *type
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Loads a PKCS#1 or PGP private RSA key file
|
||||
*/
|
||||
err_t
|
||||
load_rsa_private_key(const char* filename, prompt_pass_t *pass
|
||||
, RSA_private_key_t *key)
|
||||
err_t load_rsa_private_key(char* filename, prompt_pass_t *pass,
|
||||
RSA_private_key_t *key)
|
||||
{
|
||||
err_t ugh = NULL;
|
||||
bool pgp = FALSE;
|
||||
chunk_t blob = chunk_empty;
|
||||
|
||||
const char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
|
||||
char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
|
||||
|
||||
if (load_coded_file(path, pass, "private key", &blob, &pgp))
|
||||
{
|
||||
@@ -153,11 +151,11 @@ load_rsa_private_key(const char* filename, prompt_pass_t *pass
|
||||
|
||||
return ugh;
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* Loads a X.509 or OpenPGP certificate
|
||||
*/
|
||||
bool
|
||||
load_cert(const char *filename, const char *label, cert_t *cert)
|
||||
bool load_cert(char *filename, const char *label, cert_t *cert)
|
||||
{
|
||||
bool pgp = FALSE;
|
||||
chunk_t blob = chunk_empty;
|
||||
@@ -206,42 +204,38 @@ load_cert(const char *filename, const char *label, cert_t *cert)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Loads a host certificate
|
||||
*/
|
||||
bool
|
||||
load_host_cert(const char *filename, cert_t *cert)
|
||||
bool load_host_cert(char *filename, cert_t *cert)
|
||||
{
|
||||
const char *path = concatenate_paths(HOST_CERT_PATH, filename);
|
||||
char *path = concatenate_paths(HOST_CERT_PATH, filename);
|
||||
|
||||
return load_cert(path, "host cert", cert);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Loads a CA certificate
|
||||
*/
|
||||
bool
|
||||
load_ca_cert(const char *filename, cert_t *cert)
|
||||
bool load_ca_cert(char *filename, cert_t *cert)
|
||||
{
|
||||
const char *path = concatenate_paths(CA_CERT_PATH, filename);
|
||||
char *path = concatenate_paths(CA_CERT_PATH, filename);
|
||||
|
||||
return load_cert(path, "CA cert", cert);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* establish equality of two certificates
|
||||
*/
|
||||
bool
|
||||
same_cert(const cert_t *a, const cert_t *b)
|
||||
bool same_cert(const cert_t *a, const cert_t *b)
|
||||
{
|
||||
return a->type == b->type && a->u.x509 == b->u.x509;
|
||||
}
|
||||
|
||||
/* for each link pointing to the certif icate
|
||||
" increase the count by one
|
||||
/**
|
||||
* for each link pointing to the certificate increase the count by one
|
||||
*/
|
||||
void
|
||||
share_cert(cert_t cert)
|
||||
void share_cert(cert_t cert)
|
||||
{
|
||||
switch (cert.type)
|
||||
{
|
||||
|
||||
+5
-6
@@ -61,15 +61,14 @@ extern const cert_t empty_cert;
|
||||
*/
|
||||
extern bool no_cr_send;
|
||||
|
||||
extern err_t load_rsa_private_key(const char* filename, prompt_pass_t *pass
|
||||
extern err_t load_rsa_private_key(char* filename, prompt_pass_t *pass
|
||||
, RSA_private_key_t *key);
|
||||
extern chunk_t get_mycert(cert_t cert);
|
||||
extern bool load_coded_file(const char *filename, prompt_pass_t *pass
|
||||
extern bool load_coded_file(char *filename, prompt_pass_t *pass
|
||||
, const char *type, chunk_t *blob, bool *pgp);
|
||||
extern bool load_cert(const char *filename, const char *label
|
||||
, cert_t *cert);
|
||||
extern bool load_host_cert(const char *filename, cert_t *cert);
|
||||
extern bool load_ca_cert(const char *filename, cert_t *cert);
|
||||
extern bool load_cert(char *filename, const char *label, cert_t *cert);
|
||||
extern bool load_host_cert(char *filename, cert_t *cert);
|
||||
extern bool load_ca_cert(char *filename, cert_t *cert);
|
||||
extern bool same_cert(const cert_t *a, const cert_t *b);
|
||||
extern void share_cert(cert_t cert);
|
||||
extern void release_cert(cert_t cert);
|
||||
|
||||
@@ -701,8 +701,7 @@ unshare_connection_strings(struct connection *c)
|
||||
alg_info_addref((struct alg_info *)c->alg_info_ike);
|
||||
}
|
||||
|
||||
static void
|
||||
load_end_certificate(const char *filename, struct end *dst)
|
||||
static void load_end_certificate(char *filename, struct end *dst)
|
||||
{
|
||||
time_t valid_until;
|
||||
cert_t cert;
|
||||
|
||||
+99
-102
@@ -1,5 +1,7 @@
|
||||
/* Support of X.509 certificate revocation lists (CRLs)
|
||||
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
|
||||
* Copyright (C) 2000-2009 Andreas Steffen
|
||||
*
|
||||
* HSR 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
|
||||
@@ -25,11 +27,13 @@
|
||||
#include <freeswan.h>
|
||||
#include <ipsec_policy.h>
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "asn1.h"
|
||||
#include <asn1/oid.h>
|
||||
#include "x509.h"
|
||||
#include "crl.h"
|
||||
#include "ca.h"
|
||||
@@ -43,64 +47,64 @@
|
||||
|
||||
static x509crl_t *x509crls = NULL;
|
||||
|
||||
/* ASN.1 definition of an X.509 certificate list */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of an X.509 certificate revocation list
|
||||
*/
|
||||
static const asn1Object_t crlObjects[] = {
|
||||
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "version", ASN1_INTEGER, ASN1_OPT |
|
||||
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
|
||||
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "version", ASN1_INTEGER, ASN1_OPT |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
|
||||
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
|
||||
{ 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
|
||||
{ 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
|
||||
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
|
||||
{ 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
|
||||
{ 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 8 */
|
||||
{ 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
|
||||
{ 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
|
||||
{ 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
|
||||
{ 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 12 */
|
||||
{ 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
|
||||
{ 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
|
||||
{ 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
{ 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
|
||||
{ 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
|
||||
{ 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
|
||||
{ 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 12 */
|
||||
{ 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
|
||||
{ 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
|
||||
{ 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 15 */
|
||||
{ 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
|
||||
{ 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
|
||||
{ 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
|
||||
{ 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
{ 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
|
||||
{ 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
|
||||
{ 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
|
||||
{ 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
|
||||
ASN1_BODY }, /* 23 */
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
|
||||
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
|
||||
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
|
||||
};
|
||||
|
||||
#define CRL_OBJ_CERTIFICATE_LIST 0
|
||||
#define CRL_OBJ_TBS_CERT_LIST 1
|
||||
#define CRL_OBJ_VERSION 2
|
||||
#define CRL_OBJ_SIG_ALG 4
|
||||
#define CRL_OBJ_ISSUER 5
|
||||
#define CRL_OBJ_THIS_UPDATE 6
|
||||
#define CRL_OBJ_NEXT_UPDATE 7
|
||||
#define CRL_OBJ_USER_CERTIFICATE 10
|
||||
#define CRL_OBJ_REVOCATION_DATE 11
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
|
||||
#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
|
||||
#define CRL_OBJ_EXTN_ID 22
|
||||
#define CRL_OBJ_CRITICAL 23
|
||||
#define CRL_OBJ_EXTN_VALUE 24
|
||||
#define CRL_OBJ_ALGORITHM 27
|
||||
#define CRL_OBJ_SIGNATURE 28
|
||||
#define CRL_OBJ_ROOF 29
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
|
||||
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
|
||||
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define CRL_OBJ_CERTIFICATE_LIST 0
|
||||
#define CRL_OBJ_TBS_CERT_LIST 1
|
||||
#define CRL_OBJ_VERSION 2
|
||||
#define CRL_OBJ_SIG_ALG 4
|
||||
#define CRL_OBJ_ISSUER 5
|
||||
#define CRL_OBJ_THIS_UPDATE 6
|
||||
#define CRL_OBJ_NEXT_UPDATE 7
|
||||
#define CRL_OBJ_USER_CERTIFICATE 10
|
||||
#define CRL_OBJ_REVOCATION_DATE 11
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
|
||||
#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
|
||||
#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
|
||||
#define CRL_OBJ_EXTN_ID 22
|
||||
#define CRL_OBJ_CRITICAL 23
|
||||
#define CRL_OBJ_EXTN_VALUE 24
|
||||
#define CRL_OBJ_ALGORITHM 27
|
||||
#define CRL_OBJ_SIGNATURE 28
|
||||
|
||||
const x509crl_t empty_x509crl = {
|
||||
NULL , /* *next */
|
||||
@@ -126,11 +130,10 @@ const x509crl_t empty_x509crl = {
|
||||
{ NULL, 0 } /* signature */
|
||||
};
|
||||
|
||||
/*
|
||||
* get the X.509 CRL with a given issuer
|
||||
/**
|
||||
* Get the X.509 CRL with a given issuer
|
||||
*/
|
||||
static x509crl_t*
|
||||
get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
|
||||
static x509crl_t* get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
|
||||
{
|
||||
x509crl_t *crl = x509crls;
|
||||
x509crl_t *prev_crl = NULL;
|
||||
@@ -156,11 +159,10 @@ get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* free the dynamic memory used to store revoked certificates
|
||||
/**
|
||||
* Free the dynamic memory used to store revoked certificates
|
||||
*/
|
||||
static void
|
||||
free_revoked_certs(revokedCert_t* revokedCerts)
|
||||
static void free_revoked_certs(revokedCert_t* revokedCerts)
|
||||
{
|
||||
while (revokedCerts != NULL)
|
||||
{
|
||||
@@ -170,11 +172,10 @@ free_revoked_certs(revokedCert_t* revokedCerts)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* free the dynamic memory used to store CRLs
|
||||
/**
|
||||
* Free the dynamic memory used to store CRLs
|
||||
*/
|
||||
void
|
||||
free_crl(x509crl_t *crl)
|
||||
void free_crl(x509crl_t *crl)
|
||||
{
|
||||
free_revoked_certs(crl->revokedCertificates);
|
||||
free_generalNames(crl->distributionPoints, TRUE);
|
||||
@@ -182,8 +183,7 @@ free_crl(x509crl_t *crl)
|
||||
free(crl);
|
||||
}
|
||||
|
||||
static void
|
||||
free_first_crl(void)
|
||||
static void free_first_crl(void)
|
||||
{
|
||||
x509crl_t *crl = x509crls;
|
||||
|
||||
@@ -191,8 +191,7 @@ free_first_crl(void)
|
||||
free_crl(crl);
|
||||
}
|
||||
|
||||
void
|
||||
free_crls(void)
|
||||
void free_crls(void)
|
||||
{
|
||||
lock_crl_list("free_crls");
|
||||
|
||||
@@ -202,11 +201,10 @@ free_crls(void)
|
||||
unlock_crl_list("free_crls");
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Insert X.509 CRL into chained list
|
||||
*/
|
||||
bool
|
||||
insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
|
||||
bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
|
||||
{
|
||||
x509crl_t *crl = malloc_thing(x509crl_t);
|
||||
|
||||
@@ -322,11 +320,10 @@ insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Loads CRLs
|
||||
*/
|
||||
void
|
||||
load_crls(void)
|
||||
void load_crls(void)
|
||||
{
|
||||
struct dirent **filelist;
|
||||
u_char buf[BUF_LEN];
|
||||
@@ -376,11 +373,10 @@ load_crls(void)
|
||||
ignore_result(chdir(save_dir));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Parses a CRL revocation reason code
|
||||
*/
|
||||
static crl_reason_t
|
||||
parse_crl_reasonCode(chunk_t object)
|
||||
static crl_reason_t parse_crl_reasonCode(chunk_t object)
|
||||
{
|
||||
crl_reason_t reason = REASON_UNSPECIFIED;
|
||||
|
||||
@@ -399,27 +395,22 @@ parse_crl_reasonCode(chunk_t object)
|
||||
/*
|
||||
* Parses an X.509 CRL
|
||||
*/
|
||||
bool
|
||||
parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t extnID;
|
||||
chunk_t userCertificate = chunk_empty;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
bool success = FALSE;
|
||||
bool critical;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(crlObjects, blob);
|
||||
|
||||
while (objectID < CRL_OBJ_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
/* those objects which will parsed further need the next higher level */
|
||||
level++;
|
||||
u_int level = parser->get_level(parser)+1;
|
||||
|
||||
switch (objectID) {
|
||||
case CRL_OBJ_CERTIFICATE_LIST:
|
||||
@@ -435,7 +426,7 @@ parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
)
|
||||
break;
|
||||
case CRL_OBJ_SIG_ALG:
|
||||
crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
|
||||
crl->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case CRL_OBJ_ISSUER:
|
||||
crl->issuer = object;
|
||||
@@ -445,10 +436,10 @@ parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
)
|
||||
break;
|
||||
case CRL_OBJ_THIS_UPDATE:
|
||||
crl->thisUpdate = parse_time(object, level);
|
||||
crl->thisUpdate = asn1_parse_time(object, level);
|
||||
break;
|
||||
case CRL_OBJ_NEXT_UPDATE:
|
||||
crl->nextUpdate = parse_time(object, level);
|
||||
crl->nextUpdate = asn1_parse_time(object, level);
|
||||
break;
|
||||
case CRL_OBJ_USER_CERTIFICATE:
|
||||
userCertificate = object;
|
||||
@@ -460,7 +451,7 @@ parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
|
||||
revokedCert_t *revokedCert = malloc_thing(revokedCert_t);
|
||||
revokedCert->userCertificate = userCertificate;
|
||||
revokedCert->revocationDate = parse_time(object, level);
|
||||
revokedCert->revocationDate = asn1_parse_time(object, level);
|
||||
revokedCert->revocationReason = REASON_UNSPECIFIED;
|
||||
revokedCert->next = crl->revokedCertificates;
|
||||
crl->revokedCertificates = revokedCert;
|
||||
@@ -494,14 +485,17 @@ parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
}
|
||||
else if (extn_oid == OID_CRL_NUMBER)
|
||||
{
|
||||
if (!parse_asn1_simple_object(&object, ASN1_INTEGER, level, "crlNumber"))
|
||||
return FALSE;
|
||||
if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
|
||||
level, "crlNumber"))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
crl->crlNumber = object;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CRL_OBJ_ALGORITHM:
|
||||
crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
|
||||
crl->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case CRL_OBJ_SIGNATURE:
|
||||
crl->signature = object;
|
||||
@@ -509,10 +503,13 @@ parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
success = parser->success(parser);
|
||||
time(&crl->installed);
|
||||
return TRUE;
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
return success;
|
||||
}
|
||||
|
||||
/* Checks if the current certificate is revoked. It goes through the
|
||||
|
||||
+1
-2
@@ -68,8 +68,7 @@ temporary_cyclic_buffer(void)
|
||||
/* concatenates two sub paths into a string with a maximum size of BUF_LEN
|
||||
* use for temporary storage only
|
||||
*/
|
||||
const char*
|
||||
concatenate_paths(const char *a, const char *b)
|
||||
char* concatenate_paths(char *a, char *b)
|
||||
{
|
||||
char *c;
|
||||
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ extern void *clone_bytes(const void *orig, size_t size);
|
||||
{ memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;}
|
||||
|
||||
extern char* temporary_cyclic_buffer(void);
|
||||
extern const char* concatenate_paths(const char *a, const char *b);
|
||||
extern char* concatenate_paths(char *a, char *b);
|
||||
|
||||
/* move a chunk to a memory position and free it after insertion */
|
||||
extern void mv_chunk(u_char **pos, chunk_t content);
|
||||
|
||||
+2
-1
@@ -38,11 +38,12 @@
|
||||
#include <ldap.h>
|
||||
#endif
|
||||
|
||||
#include "asn1/asn1.h"
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
#include "id.h"
|
||||
#include "asn1.h"
|
||||
#include "pem.h"
|
||||
#include "x509.h"
|
||||
#include "ca.h"
|
||||
|
||||
@@ -58,7 +58,6 @@
|
||||
#include "whack.h"
|
||||
#include "fetch.h"
|
||||
#include "pkcs7.h"
|
||||
#include "asn1.h"
|
||||
|
||||
#include "sha1.h"
|
||||
#include "md5.h"
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include <utils.h>
|
||||
#include <asn1/asn1.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "mp_defs.h"
|
||||
@@ -68,3 +71,17 @@ n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen)
|
||||
mpz_add_ui(mp, mp, nbytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */
|
||||
chunk_t n = mpz_to_n(value, size);
|
||||
|
||||
return asn1_wrap(ASN1_INTEGER, "m", n);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -20,10 +20,11 @@
|
||||
|
||||
#include <gmp.h>
|
||||
|
||||
#include "defs.h"
|
||||
#include <utils.h>
|
||||
|
||||
extern void n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen);
|
||||
extern chunk_t mpz_to_n(const MP_INT *mp, size_t bytes);
|
||||
extern chunk_t asn1_integer_from_mpz(const mpz_t value);
|
||||
|
||||
/* var := mod(base ** exp, mod), ensuring var is mpz_inited */
|
||||
#define mpz_init_powm(flag, var, base, exp, mod) { \
|
||||
|
||||
+285
-295
@@ -26,6 +26,10 @@
|
||||
#include <freeswan.h>
|
||||
#include <ipsec_policy.h>
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "log.h"
|
||||
@@ -33,10 +37,8 @@
|
||||
#include "crl.h"
|
||||
#include "ca.h"
|
||||
#include "rnd.h"
|
||||
#include "asn1.h"
|
||||
#include "certs.h"
|
||||
#include "smartcard.h"
|
||||
#include <asn1/oid.h>
|
||||
#include "whack.h"
|
||||
#include "pkcs1.h"
|
||||
#include "keys.h"
|
||||
@@ -160,131 +162,137 @@ static smartcard_t *ocsp_requestor_sc = NULL;
|
||||
|
||||
static const struct RSA_private_key *ocsp_requestor_pri = NULL;
|
||||
|
||||
/* asn.1 definitions for parsing */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of ocspResponse
|
||||
*/
|
||||
static const asn1Object_t ocspResponseObjects[] = {
|
||||
{ 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
|
||||
{ 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
|
||||
{ 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
|
||||
{ 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
|
||||
{ 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 6 */
|
||||
{ 0, "OCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "responseStatus", ASN1_ENUMERATED, ASN1_BODY }, /* 1 */
|
||||
{ 1, "responseBytesContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 2 */
|
||||
{ 2, "responseBytes", ASN1_SEQUENCE, ASN1_NONE }, /* 3 */
|
||||
{ 3, "responseType", ASN1_OID, ASN1_BODY }, /* 4 */
|
||||
{ 3, "response", ASN1_OCTET_STRING, ASN1_BODY }, /* 5 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
#define OCSP_RESPONSE_STATUS 1
|
||||
#define OCSP_RESPONSE_TYPE 4
|
||||
#define OCSP_RESPONSE 5
|
||||
|
||||
#define OCSP_RESPONSE_STATUS 1
|
||||
#define OCSP_RESPONSE_TYPE 4
|
||||
#define OCSP_RESPONSE 5
|
||||
#define OCSP_RESPONSE_ROOF 7
|
||||
|
||||
/**
|
||||
* ASN.1 definition of basicResponse
|
||||
*/
|
||||
static const asn1Object_t basicResponseObjects[] = {
|
||||
{ 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
|
||||
ASN1_DEF }, /* 2 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
|
||||
{ 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
|
||||
{ 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
|
||||
{ 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
|
||||
{ 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
|
||||
{ 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
|
||||
{ 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
|
||||
ASN1_DEF }, /* 16 */
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
|
||||
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
|
||||
{ 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
|
||||
{ 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
|
||||
{ 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
|
||||
{ 3, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 24 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 26 */
|
||||
{ 0, "BasicOCSPResponse", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "tbsResponseData", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
|
||||
{ 2, "versionContext", ASN1_CONTEXT_C_0, ASN1_NONE |
|
||||
ASN1_DEF }, /* 2 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
|
||||
{ 2, "responderIdContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 4 */
|
||||
{ 3, "responderIdByName", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 2, "responderIdContext", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 7 */
|
||||
{ 3, "responderIdByKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 8 */
|
||||
{ 2, "end choice", ASN1_EOC, ASN1_END }, /* 9 */
|
||||
{ 2, "producedAt", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 10 */
|
||||
{ 2, "responses", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
|
||||
{ 2, "responseExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
|
||||
{ 3, "responseExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 13 */
|
||||
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 14 */
|
||||
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 15 */
|
||||
{ 5, "critical", ASN1_BOOLEAN, ASN1_BODY |
|
||||
ASN1_DEF }, /* 16 */
|
||||
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 17 */
|
||||
{ 4, "end loop", ASN1_EOC, ASN1_END }, /* 18 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
|
||||
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 20 */
|
||||
{ 1, "signature", ASN1_BIT_STRING, ASN1_BODY }, /* 21 */
|
||||
{ 1, "certsContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 22 */
|
||||
{ 2, "certs", ASN1_SEQUENCE, ASN1_LOOP }, /* 23 */
|
||||
{ 3, "certificate", ASN1_SEQUENCE, ASN1_RAW }, /* 24 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
#define BASIC_RESPONSE_TBS_DATA 1
|
||||
#define BASIC_RESPONSE_VERSION 3
|
||||
#define BASIC_RESPONSE_ID_BY_NAME 5
|
||||
#define BASIC_RESPONSE_ID_BY_KEY 8
|
||||
#define BASIC_RESPONSE_PRODUCED_AT 10
|
||||
#define BASIC_RESPONSE_RESPONSES 11
|
||||
#define BASIC_RESPONSE_EXT_ID 15
|
||||
#define BASIC_RESPONSE_CRITICAL 16
|
||||
#define BASIC_RESPONSE_EXT_VALUE 17
|
||||
#define BASIC_RESPONSE_ALGORITHM 20
|
||||
#define BASIC_RESPONSE_SIGNATURE 21
|
||||
#define BASIC_RESPONSE_CERTIFICATE 24
|
||||
|
||||
#define BASIC_RESPONSE_TBS_DATA 1
|
||||
#define BASIC_RESPONSE_VERSION 3
|
||||
#define BASIC_RESPONSE_ID_BY_NAME 5
|
||||
#define BASIC_RESPONSE_ID_BY_KEY 8
|
||||
#define BASIC_RESPONSE_PRODUCED_AT 10
|
||||
#define BASIC_RESPONSE_RESPONSES 11
|
||||
#define BASIC_RESPONSE_EXT_ID 15
|
||||
#define BASIC_RESPONSE_CRITICAL 16
|
||||
#define BASIC_RESPONSE_EXT_VALUE 17
|
||||
#define BASIC_RESPONSE_ALGORITHM 20
|
||||
#define BASIC_RESPONSE_SIGNATURE 21
|
||||
#define BASIC_RESPONSE_CERTIFICATE 24
|
||||
#define BASIC_RESPONSE_ROOF 27
|
||||
|
||||
/**
|
||||
* ASN.1 definition of responses
|
||||
*/
|
||||
static const asn1Object_t responsesObjects[] = {
|
||||
{ 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
|
||||
{ 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
|
||||
{ 0, "end loop", ASN1_EOC, ASN1_END } /* 2 */
|
||||
{ 0, "responses", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */
|
||||
{ 1, "singleResponse", ASN1_EOC, ASN1_RAW }, /* 1 */
|
||||
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 2 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
#define RESPONSES_SINGLE_RESPONSE 1
|
||||
|
||||
#define RESPONSES_SINGLE_RESPONSE 1
|
||||
#define RESPONSES_ROOF 3
|
||||
|
||||
/**
|
||||
* ASN.1 definition of singleResponse
|
||||
*/
|
||||
static const asn1Object_t singleResponseObjects[] = {
|
||||
{ 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
|
||||
{ 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
||||
{ 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
|
||||
{ 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
|
||||
{ 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
|
||||
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
|
||||
{ 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
|
||||
{ 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
|
||||
{ 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
|
||||
{ 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
|
||||
{ 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
|
||||
{ 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
|
||||
{ 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
|
||||
{ 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
|
||||
{ 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
|
||||
{ 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
|
||||
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
|
||||
{ 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
|
||||
{ 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
|
||||
ASN1_DEF }, /* 24 */
|
||||
{ 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 27 */
|
||||
{ 0, "singleResponse", ASN1_SEQUENCE, ASN1_BODY }, /* 0 */
|
||||
{ 1, "certID", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
||||
{ 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 2 */
|
||||
{ 2, "issuerNameHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 3 */
|
||||
{ 2, "issuerKeyHash", ASN1_OCTET_STRING, ASN1_BODY }, /* 4 */
|
||||
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 5 */
|
||||
{ 1, "certStatusGood", ASN1_CONTEXT_S_0, ASN1_OPT }, /* 6 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 7 */
|
||||
{ 1, "certStatusRevoked", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 8 */
|
||||
{ 2, "revocationTime", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 9 */
|
||||
{ 2, "revocationReason", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 10 */
|
||||
{ 3, "crlReason", ASN1_ENUMERATED, ASN1_BODY }, /* 11 */
|
||||
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 12 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
|
||||
{ 1, "certStatusUnknown", ASN1_CONTEXT_S_2, ASN1_OPT }, /* 14 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
|
||||
{ 1, "thisUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 16 */
|
||||
{ 1, "nextUpdateContext", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 17 */
|
||||
{ 2, "nextUpdate", ASN1_GENERALIZEDTIME, ASN1_BODY }, /* 18 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 19 */
|
||||
{ 1, "singleExtensionsContext", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 20 */
|
||||
{ 2, "singleExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 21 */
|
||||
{ 3, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 22 */
|
||||
{ 4, "extnID", ASN1_OID, ASN1_BODY }, /* 23 */
|
||||
{ 4, "critical", ASN1_BOOLEAN, ASN1_BODY |
|
||||
ASN1_DEF }, /* 24 */
|
||||
{ 4, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 25 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 26 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 27 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
#define SINGLE_RESPONSE_ALGORITHM 2
|
||||
#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
|
||||
#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
|
||||
#define SINGLE_RESPONSE_SERIAL_NUMBER 5
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
|
||||
#define SINGLE_RESPONSE_THIS_UPDATE 16
|
||||
#define SINGLE_RESPONSE_NEXT_UPDATE 18
|
||||
#define SINGLE_RESPONSE_EXT_ID 23
|
||||
#define SINGLE_RESPONSE_CRITICAL 24
|
||||
#define SINGLE_RESPONSE_EXT_VALUE 25
|
||||
|
||||
#define SINGLE_RESPONSE_ALGORITHM 2
|
||||
#define SINGLE_RESPONSE_ISSUER_NAME_HASH 3
|
||||
#define SINGLE_RESPONSE_ISSUER_KEY_HASH 4
|
||||
#define SINGLE_RESPONSE_SERIAL_NUMBER 5
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_GOOD 6
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_REVOKED 8
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME 9
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_CRL_REASON 11
|
||||
#define SINGLE_RESPONSE_CERT_STATUS_UNKNOWN 14
|
||||
#define SINGLE_RESPONSE_THIS_UPDATE 16
|
||||
#define SINGLE_RESPONSE_NEXT_UPDATE 18
|
||||
#define SINGLE_RESPONSE_EXT_ID 23
|
||||
#define SINGLE_RESPONSE_CRITICAL 24
|
||||
#define SINGLE_RESPONSE_EXT_VALUE 25
|
||||
#define SINGLE_RESPONSE_ROOF 28
|
||||
|
||||
/* build an ocsp location from certificate information
|
||||
/*
|
||||
* Build an ocsp location from certificate information
|
||||
* without unsharing its contents
|
||||
*/
|
||||
static bool
|
||||
build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
|
||||
static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
|
||||
{
|
||||
static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */
|
||||
|
||||
@@ -330,11 +338,10 @@ build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* compare two ocsp locations for equality
|
||||
/**
|
||||
* Compare two ocsp locations for equality
|
||||
*/
|
||||
static bool
|
||||
same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
|
||||
static bool same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
|
||||
{
|
||||
return ((a->authKeyID.ptr != NULL)
|
||||
? same_keyid(a->authKeyID, b->authKeyID)
|
||||
@@ -343,11 +350,10 @@ same_ocsp_location(const ocsp_location_t *a, const ocsp_location_t *b)
|
||||
&& chunk_equals(a->uri, b->uri);
|
||||
}
|
||||
|
||||
/*
|
||||
* find an existing ocsp location in a chained list
|
||||
/**
|
||||
* Find an existing ocsp location in a chained list
|
||||
*/
|
||||
ocsp_location_t*
|
||||
get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
|
||||
ocsp_location_t* get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
|
||||
{
|
||||
|
||||
while (chain != NULL)
|
||||
@@ -359,12 +365,14 @@ get_ocsp_location(const ocsp_location_t * loc, ocsp_location_t *chain)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* retrieves the status of a cert from the ocsp cache
|
||||
/**
|
||||
* Retrieves the status of a cert from the ocsp cache
|
||||
* returns CERT_UNDEFINED if no status is found
|
||||
*/
|
||||
static cert_status_t
|
||||
get_ocsp_status(const ocsp_location_t *loc, chunk_t serialNumber
|
||||
,time_t *nextUpdate, time_t *revocationTime, crl_reason_t *revocationReason)
|
||||
static cert_status_t get_ocsp_status(const ocsp_location_t *loc,
|
||||
chunk_t serialNumber,
|
||||
time_t *nextUpdate, time_t *revocationTime,
|
||||
crl_reason_t *revocationReason)
|
||||
{
|
||||
ocsp_certinfo_t *certinfo, **certinfop;
|
||||
int cmp = -1;
|
||||
@@ -399,12 +407,12 @@ get_ocsp_status(const ocsp_location_t *loc, chunk_t serialNumber
|
||||
return CERT_UNDEFINED;
|
||||
}
|
||||
|
||||
/*
|
||||
* verify the ocsp status of a certificate
|
||||
/**
|
||||
* Verify the ocsp status of a certificate
|
||||
*/
|
||||
cert_status_t
|
||||
verify_by_ocsp(const x509cert_t *cert, time_t *until
|
||||
, time_t *revocationDate, crl_reason_t *revocationReason)
|
||||
cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until,
|
||||
time_t *revocationDate,
|
||||
crl_reason_t *revocationReason)
|
||||
{
|
||||
cert_status_t status;
|
||||
ocsp_location_t location;
|
||||
@@ -434,11 +442,10 @@ verify_by_ocsp(const x509cert_t *cert, time_t *until
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if an ocsp status is about to expire
|
||||
/**
|
||||
* Check if an ocsp status is about to expire
|
||||
*/
|
||||
void
|
||||
check_ocsp(void)
|
||||
void check_ocsp(void)
|
||||
{
|
||||
ocsp_location_t *location;
|
||||
|
||||
@@ -485,21 +492,19 @@ check_ocsp(void)
|
||||
unlock_ocsp_cache("check_ocsp");
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* frees the allocated memory of a certinfo struct
|
||||
*/
|
||||
static void
|
||||
free_certinfo(ocsp_certinfo_t *certinfo)
|
||||
static void free_certinfo(ocsp_certinfo_t *certinfo)
|
||||
{
|
||||
free(certinfo->serialNumber.ptr);
|
||||
free(certinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* frees all certinfos in a chained list
|
||||
*/
|
||||
static void
|
||||
free_certinfos(ocsp_certinfo_t *chain)
|
||||
static void free_certinfos(ocsp_certinfo_t *chain)
|
||||
{
|
||||
ocsp_certinfo_t *certinfo;
|
||||
|
||||
@@ -511,11 +516,10 @@ free_certinfos(ocsp_certinfo_t *chain)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* frees the memory allocated to an ocsp location including all certinfos
|
||||
/**
|
||||
* Frees the memory allocated to an ocsp location including all certinfos
|
||||
*/
|
||||
static void
|
||||
free_ocsp_location(ocsp_location_t* location)
|
||||
static void free_ocsp_location(ocsp_location_t* location)
|
||||
{
|
||||
free(location->issuer.ptr);
|
||||
free(location->authNameID.ptr);
|
||||
@@ -527,10 +531,9 @@ free_ocsp_location(ocsp_location_t* location)
|
||||
}
|
||||
|
||||
/*
|
||||
* free a chained list of ocsp locations
|
||||
* Free a chained list of ocsp locations
|
||||
*/
|
||||
void
|
||||
free_ocsp_locations(ocsp_location_t **chain)
|
||||
void free_ocsp_locations(ocsp_location_t **chain)
|
||||
{
|
||||
while (*chain != NULL)
|
||||
{
|
||||
@@ -540,33 +543,30 @@ free_ocsp_locations(ocsp_location_t **chain)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* free the ocsp cache
|
||||
/**
|
||||
* Free the ocsp cache
|
||||
*/
|
||||
void
|
||||
free_ocsp_cache(void)
|
||||
void free_ocsp_cache(void)
|
||||
{
|
||||
lock_ocsp_cache("free_ocsp_cache");
|
||||
free_ocsp_locations(&ocsp_cache);
|
||||
unlock_ocsp_cache("free_ocsp_cache");
|
||||
}
|
||||
|
||||
/*
|
||||
* frees the ocsp cache and global variables
|
||||
/**
|
||||
* Frees the ocsp cache and global variables
|
||||
*/
|
||||
void
|
||||
free_ocsp(void)
|
||||
void free_ocsp(void)
|
||||
{
|
||||
free(ocsp_default_uri.ptr);
|
||||
free_ocsp_cache();
|
||||
}
|
||||
|
||||
/*
|
||||
* list a chained list of ocsp_locations
|
||||
/**
|
||||
* List a chained list of ocsp_locations
|
||||
*/
|
||||
void
|
||||
list_ocsp_locations(ocsp_location_t *location, bool requests, bool utc
|
||||
, bool strict)
|
||||
void list_ocsp_locations(ocsp_location_t *location, bool requests,
|
||||
bool utc, bool strict)
|
||||
{
|
||||
bool first = TRUE;
|
||||
|
||||
@@ -644,19 +644,17 @@ list_ocsp_locations(ocsp_location_t *location, bool requests, bool utc
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* list the ocsp cache
|
||||
/**
|
||||
* List the ocsp cache
|
||||
*/
|
||||
void
|
||||
list_ocsp_cache(bool utc, bool strict)
|
||||
void list_ocsp_cache(bool utc, bool strict)
|
||||
{
|
||||
lock_ocsp_cache("list_ocsp_cache");
|
||||
list_ocsp_locations(ocsp_cache, FALSE, utc, strict);
|
||||
unlock_ocsp_cache("list_ocsp_cache");
|
||||
}
|
||||
|
||||
static bool
|
||||
get_ocsp_requestor_cert(ocsp_location_t *location)
|
||||
static bool get_ocsp_requestor_cert(ocsp_location_t *location)
|
||||
{
|
||||
x509cert_t *cert = NULL;
|
||||
|
||||
@@ -718,9 +716,8 @@ get_ocsp_requestor_cert(ocsp_location_t *location)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static chunk_t
|
||||
generate_signature(chunk_t digest, smartcard_t *sc
|
||||
, const RSA_private_key_t *pri)
|
||||
static chunk_t generate_signature(chunk_t digest, smartcard_t *sc,
|
||||
const RSA_private_key_t *pri)
|
||||
{
|
||||
chunk_t sigdata;
|
||||
u_char *pos;
|
||||
@@ -750,7 +747,7 @@ generate_signature(chunk_t digest, smartcard_t *sc
|
||||
, (int)sc->slot, sc->id)
|
||||
)
|
||||
|
||||
pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
|
||||
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
|
||||
*pos++ = 0x00;
|
||||
scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen);
|
||||
if (!pkcs11_keep_state)
|
||||
@@ -760,20 +757,18 @@ generate_signature(chunk_t digest, smartcard_t *sc
|
||||
{
|
||||
/* RSA signature is done in software */
|
||||
siglen = pri->pub.k;
|
||||
pos = build_asn1_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
|
||||
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
|
||||
*pos++ = 0x00;
|
||||
sign_hash(pri, digest.ptr, digest.len, pos, siglen);
|
||||
}
|
||||
return sigdata;
|
||||
}
|
||||
|
||||
/*
|
||||
* build signature into ocsp request
|
||||
* gets built only if a request cert with
|
||||
* a corresponding private key is found
|
||||
/**
|
||||
* build signature into ocsp request gets built only if a request cert
|
||||
* with a corresponding private key is found
|
||||
*/
|
||||
static chunk_t
|
||||
build_signature(chunk_t tbsRequest)
|
||||
static chunk_t build_signature(chunk_t tbsRequest)
|
||||
{
|
||||
chunk_t sigdata, certs;
|
||||
chunk_t digest_info;
|
||||
@@ -788,7 +783,7 @@ build_signature(chunk_t tbsRequest)
|
||||
* an ASN.1 structure for encryption
|
||||
*/
|
||||
digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
|
||||
, ASN1_sha1_id
|
||||
, asn1_algorithmIdentifier(OID_SHA1)
|
||||
, asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
|
||||
|
||||
/* generate the RSA signature */
|
||||
@@ -811,21 +806,21 @@ build_signature(chunk_t tbsRequest)
|
||||
/* build signature comprising algorithm, signature and cert */
|
||||
return asn1_wrap(ASN1_CONTEXT_C_0, "m"
|
||||
, asn1_wrap(ASN1_SEQUENCE, "cmm"
|
||||
, ASN1_sha1WithRSA_id
|
||||
, asn1_algorithmIdentifier(OID_SHA1_WITH_RSA)
|
||||
, sigdata
|
||||
, certs
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/* build request (into requestList)
|
||||
/**
|
||||
* Build request (into requestList)
|
||||
* no singleRequestExtensions used
|
||||
*/
|
||||
static chunk_t
|
||||
build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
|
||||
static chunk_t build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
|
||||
{
|
||||
chunk_t reqCert = asn1_wrap(ASN1_SEQUENCE, "cmmm"
|
||||
, ASN1_sha1_id
|
||||
, asn1_algorithmIdentifier(OID_SHA1)
|
||||
, asn1_simple_object(ASN1_OCTET_STRING, location->authNameID)
|
||||
, asn1_simple_object(ASN1_OCTET_STRING, location->authKeyID)
|
||||
, asn1_simple_object(ASN1_INTEGER, certinfo->serialNumber));
|
||||
@@ -833,11 +828,10 @@ build_request(ocsp_location_t *location, ocsp_certinfo_t *certinfo)
|
||||
return asn1_wrap(ASN1_SEQUENCE, "m", reqCert);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* build requestList (into TBSRequest)
|
||||
*/
|
||||
static chunk_t
|
||||
build_request_list(ocsp_location_t *location)
|
||||
static chunk_t build_request_list(ocsp_location_t *location)
|
||||
{
|
||||
chunk_t requestList;
|
||||
request_list_t *reqs = NULL;
|
||||
@@ -862,8 +856,7 @@ build_request_list(ocsp_location_t *location)
|
||||
certinfo = certinfo->next;
|
||||
}
|
||||
|
||||
pos = build_asn1_object(&requestList, ASN1_SEQUENCE
|
||||
, datalen);
|
||||
pos = asn1_build_object(&requestList, ASN1_SEQUENCE, datalen);
|
||||
|
||||
/* copy all in chained list, free list afterwards */
|
||||
while (reqs != NULL)
|
||||
@@ -878,22 +871,20 @@ build_request_list(ocsp_location_t *location)
|
||||
return requestList;
|
||||
}
|
||||
|
||||
/*
|
||||
* build requestorName (into TBSRequest)
|
||||
/**
|
||||
* Build requestorName (into TBSRequest)
|
||||
*/
|
||||
static chunk_t
|
||||
build_requestor_name(void)
|
||||
static chunk_t build_requestor_name(void)
|
||||
{
|
||||
return asn1_wrap(ASN1_CONTEXT_C_1, "m"
|
||||
, asn1_simple_object(ASN1_CONTEXT_C_4
|
||||
, ocsp_requestor_cert->subject));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* build nonce extension (into requestExtensions)
|
||||
*/
|
||||
static chunk_t
|
||||
build_nonce_extension(ocsp_location_t *location)
|
||||
static chunk_t build_nonce_extension(ocsp_location_t *location)
|
||||
{
|
||||
/* generate a random nonce */
|
||||
location->nonce.ptr = malloc(NONCE_LENGTH),
|
||||
@@ -905,11 +896,10 @@ build_nonce_extension(ocsp_location_t *location)
|
||||
, asn1_simple_object(ASN1_OCTET_STRING, location->nonce));
|
||||
}
|
||||
|
||||
/*
|
||||
* build requestExtensions (into TBSRequest)
|
||||
/**
|
||||
* Build requestExtensions (into TBSRequest)
|
||||
*/
|
||||
static chunk_t
|
||||
build_request_ext(ocsp_location_t *location)
|
||||
static chunk_t build_request_ext(ocsp_location_t *location)
|
||||
{
|
||||
return asn1_wrap(ASN1_CONTEXT_C_2, "m"
|
||||
, asn1_wrap(ASN1_SEQUENCE, "mm"
|
||||
@@ -922,11 +912,10 @@ build_request_ext(ocsp_location_t *location)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* build TBSRequest (into OCSPRequest)
|
||||
/**
|
||||
* Build TBSRequest (into OCSPRequest)
|
||||
*/
|
||||
static chunk_t
|
||||
build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
|
||||
static chunk_t build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
|
||||
{
|
||||
/* version is skipped since the default is ok */
|
||||
return asn1_wrap(ASN1_SEQUENCE, "mmm"
|
||||
@@ -937,11 +926,11 @@ build_tbs_request(ocsp_location_t *location, bool has_requestor_cert)
|
||||
, build_request_ext(location));
|
||||
}
|
||||
|
||||
/* assembles an ocsp request to given location
|
||||
/**
|
||||
* Assembles an ocsp request to given location
|
||||
* and sets nonce field in location to the sent nonce
|
||||
*/
|
||||
chunk_t
|
||||
build_ocsp_request(ocsp_location_t *location)
|
||||
chunk_t build_ocsp_request(ocsp_location_t *location)
|
||||
{
|
||||
bool has_requestor_cert;
|
||||
chunk_t tbsRequest, signature;
|
||||
@@ -977,11 +966,10 @@ build_ocsp_request(ocsp_location_t *location)
|
||||
, signature);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if the OCSP response has a valid signature
|
||||
/**
|
||||
* Check if the OCSP response has a valid signature
|
||||
*/
|
||||
static bool
|
||||
valid_ocsp_response(response_t *res)
|
||||
static bool valid_ocsp_response(response_t *res)
|
||||
{
|
||||
int pathlen;
|
||||
x509cert_t *authcert;
|
||||
@@ -1086,27 +1074,25 @@ valid_ocsp_response(response_t *res)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse a basic OCSP response
|
||||
/**
|
||||
* Parse a basic OCSP response
|
||||
*/
|
||||
static bool
|
||||
parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
static bool parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level, version;
|
||||
u_int version;
|
||||
u_char buf[BUF_LEN];
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
int extn_oid = OID_UNKNOWN;
|
||||
bool success = FALSE;
|
||||
bool critical;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(basicResponseObjects, blob);
|
||||
parser->set_top_level(parser, level0);
|
||||
|
||||
while (objectID < BASIC_RESPONSE_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(basicResponseObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case BASIC_RESPONSE_TBS_DATA:
|
||||
@@ -1117,7 +1103,7 @@ parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
if (version != OCSP_BASIC_RESPONSE_VERSION)
|
||||
{
|
||||
plog("wrong ocsp basic response version (version= %i)", version);
|
||||
return FALSE;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case BASIC_RESPONSE_ID_BY_NAME:
|
||||
@@ -1131,7 +1117,7 @@ parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
res->responder_id_key = object;
|
||||
break;
|
||||
case BASIC_RESPONSE_PRODUCED_AT:
|
||||
res->produced_at = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
res->produced_at = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case BASIC_RESPONSE_RESPONSES:
|
||||
res->responses = object;
|
||||
@@ -1150,7 +1136,8 @@ parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
res->nonce = object;
|
||||
break;
|
||||
case BASIC_RESPONSE_ALGORITHM:
|
||||
res->algorithm = parse_algorithmIdentifier(object, level+1, NULL);
|
||||
res->algorithm = asn1_parse_algorithmIdentifier(object,
|
||||
parser->get_level(parser)+1, NULL);
|
||||
break;
|
||||
case BASIC_RESPONSE_SIGNATURE:
|
||||
res->signature = object;
|
||||
@@ -1162,7 +1149,7 @@ parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
|
||||
*cert = empty_x509cert;
|
||||
|
||||
if (parse_x509cert(blob, level+1, cert)
|
||||
if (parse_x509cert(blob, parser->get_level(parser)+1, cert)
|
||||
&& cert->isOcspSigner
|
||||
&& trust_authcert_candidate(cert, NULL))
|
||||
{
|
||||
@@ -1178,32 +1165,32 @@ parse_basic_ocsp_response(chunk_t blob, int level0, response_t *res)
|
||||
}
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
success = parser->success(parser);
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
return success;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* parse an ocsp response and return the result as a response_t struct
|
||||
/**
|
||||
* Parse an ocsp response and return the result as a response_t struct
|
||||
*/
|
||||
static response_status
|
||||
parse_ocsp_response(chunk_t blob, response_t * res)
|
||||
static response_status parse_ocsp_response(chunk_t blob, response_t * res)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
int ocspResponseType = OID_UNKNOWN;
|
||||
bool success = FALSE;
|
||||
response_status rStatus = STATUS_INTERNALERROR;
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(ocspResponseObjects, blob);
|
||||
|
||||
while (objectID < OCSP_RESPONSE_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(ocspResponseObjects, &objectID, &object, &level, &ctx))
|
||||
return STATUS_INTERNALERROR;
|
||||
|
||||
switch (objectID) {
|
||||
case OCSP_RESPONSE_STATUS:
|
||||
rStatus = (response_status) *object.ptr;
|
||||
@@ -1219,9 +1206,9 @@ parse_ocsp_response(chunk_t blob, response_t * res)
|
||||
case STATUS_UNAUTHORIZED:
|
||||
plog("ocsp response: server said '%s'"
|
||||
, response_status_names[rStatus]);
|
||||
return rStatus;
|
||||
goto end;
|
||||
default:
|
||||
return STATUS_INTERNALERROR;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case OCSP_RESPONSE_TYPE:
|
||||
@@ -1231,47 +1218,50 @@ parse_ocsp_response(chunk_t blob, response_t * res)
|
||||
{
|
||||
switch (ocspResponseType) {
|
||||
case OID_BASIC:
|
||||
if (!parse_basic_ocsp_response(object, level+1, res))
|
||||
return STATUS_INTERNALERROR;
|
||||
success = parse_basic_ocsp_response(object,
|
||||
parser->get_level(parser)+1, res);
|
||||
break;
|
||||
default:
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("ocsp response is not of type BASIC");
|
||||
DBG_dump_chunk("ocsp response OID: ", object);
|
||||
)
|
||||
return STATUS_INTERNALERROR;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
success &= parser->success(parser);
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
return rStatus;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse a basic OCSP response
|
||||
/**
|
||||
* Parse a basic OCSP response
|
||||
*/
|
||||
static bool
|
||||
parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
|
||||
static bool parse_ocsp_single_response(chunk_t blob, int level0,
|
||||
single_response_t *sres)
|
||||
{
|
||||
u_int level, extn_oid;
|
||||
asn1_ctx_t ctx;
|
||||
bool critical;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
u_int extn_oid;
|
||||
int objectID;
|
||||
bool critical;
|
||||
bool success = FALSE;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(singleResponseObjects, blob);
|
||||
parser->set_top_level(parser, level0);
|
||||
|
||||
while (objectID < SINGLE_RESPONSE_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(singleResponseObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case SINGLE_RESPONSE_ALGORITHM:
|
||||
sres->hash_algorithm = parse_algorithmIdentifier(object, level+1, NULL);
|
||||
sres->hash_algorithm = asn1_parse_algorithmIdentifier(object,
|
||||
parser->get_level(parser)+1, NULL);
|
||||
break;
|
||||
case SINGLE_RESPONSE_ISSUER_NAME_HASH:
|
||||
sres->issuer_name_hash = object;
|
||||
@@ -1289,7 +1279,7 @@ parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
|
||||
sres->status = CERT_REVOKED;
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_REVOCATION_TIME:
|
||||
sres->revocationTime = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
sres->revocationTime = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case SINGLE_RESPONSE_CERT_STATUS_CRL_REASON:
|
||||
sres->revocationReason = (object.len == 1)
|
||||
@@ -1299,10 +1289,10 @@ parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
|
||||
sres->status = CERT_UNKNOWN;
|
||||
break;
|
||||
case SINGLE_RESPONSE_THIS_UPDATE:
|
||||
sres->thisUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
sres->thisUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case SINGLE_RESPONSE_NEXT_UPDATE:
|
||||
sres->nextUpdate = asn1totime(&object, ASN1_GENERALIZEDTIME);
|
||||
sres->nextUpdate = asn1_to_time(&object, ASN1_GENERALIZEDTIME);
|
||||
break;
|
||||
case SINGLE_RESPONSE_EXT_ID:
|
||||
extn_oid = asn1_known_oid(object);
|
||||
@@ -1315,16 +1305,17 @@ parse_ocsp_single_response(chunk_t blob, int level0, single_response_t *sres)
|
||||
case SINGLE_RESPONSE_EXT_VALUE:
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
success = parser->success(parser);
|
||||
parser->destroy(parser);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* add an ocsp location to a chained list
|
||||
/**
|
||||
* Add an ocsp location to a chained list
|
||||
*/
|
||||
ocsp_location_t*
|
||||
add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t **chain)
|
||||
ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc,
|
||||
ocsp_location_t **chain)
|
||||
{
|
||||
ocsp_location_t *location = malloc_thing(ocsp_location_t);
|
||||
|
||||
@@ -1347,12 +1338,11 @@ add_ocsp_location(const ocsp_location_t *loc, ocsp_location_t **chain)
|
||||
return location;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* add a certinfo struct to a chained list
|
||||
*/
|
||||
void
|
||||
add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chain
|
||||
, bool request)
|
||||
void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info,
|
||||
ocsp_location_t **chain, bool request)
|
||||
{
|
||||
ocsp_location_t *location;
|
||||
ocsp_certinfo_t *certinfo, **certinfop;
|
||||
@@ -1362,7 +1352,9 @@ add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chai
|
||||
|
||||
location = get_ocsp_location(loc, *chain);
|
||||
if (location == NULL)
|
||||
{
|
||||
location = add_ocsp_location(loc, chain);
|
||||
}
|
||||
|
||||
/* traverse list of certinfos in increasing order */
|
||||
certinfop = &location->certinfo;
|
||||
@@ -1404,8 +1396,9 @@ add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chai
|
||||
certinfo->status = CERT_UNDEFINED;
|
||||
|
||||
if (cmp != 0)
|
||||
{
|
||||
certinfo->thisUpdate = now;
|
||||
|
||||
}
|
||||
certinfo->nextUpdate = UNDEFINED_TIME;
|
||||
}
|
||||
else
|
||||
@@ -1424,11 +1417,11 @@ add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info, ocsp_location_t **chai
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* process received ocsp single response and add it to ocsp cache
|
||||
/**
|
||||
* Process received ocsp single response and add it to ocsp cache
|
||||
*/
|
||||
static void
|
||||
process_single_response(ocsp_location_t *location, single_response_t *sres)
|
||||
static void process_single_response(ocsp_location_t *location,
|
||||
single_response_t *sres)
|
||||
{
|
||||
ocsp_certinfo_t *certinfo, **certinfop;
|
||||
int cmp = -1;
|
||||
@@ -1481,14 +1474,12 @@ process_single_response(ocsp_location_t *location, single_response_t *sres)
|
||||
|
||||
/* free certinfo unlinked from ocsp fetch request list */
|
||||
free_certinfo(certinfo);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* parse and verify ocsp response and update the ocsp cache
|
||||
/**
|
||||
* Parse and verify ocsp response and update the ocsp cache
|
||||
*/
|
||||
void
|
||||
parse_ocsp(ocsp_location_t *location, chunk_t blob)
|
||||
void parse_ocsp(ocsp_location_t *location, chunk_t blob)
|
||||
{
|
||||
response_t res = empty_response;
|
||||
|
||||
@@ -1523,28 +1514,27 @@ parse_ocsp(ocsp_location_t *location, chunk_t blob)
|
||||
|
||||
/* now parse the single responses one at a time */
|
||||
{
|
||||
u_int level;
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
|
||||
asn1_init(&ctx, res.responses, 0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(responsesObjects, res.responses);
|
||||
|
||||
while (objectID < RESPONSES_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(responsesObjects, &objectID, &object, &level, &ctx))
|
||||
return;
|
||||
|
||||
if (objectID == RESPONSES_SINGLE_RESPONSE)
|
||||
{
|
||||
single_response_t sres = empty_single_response;
|
||||
|
||||
if (parse_ocsp_single_response(object, level+1, &sres))
|
||||
if (!parse_ocsp_single_response(object,
|
||||
parser->get_level(parser)+1, &sres))
|
||||
{
|
||||
process_single_response(location, &sres);
|
||||
goto end;
|
||||
}
|
||||
process_single_response(location, &sres);
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
}
|
||||
}
|
||||
|
||||
+108
-126
@@ -23,11 +23,13 @@
|
||||
#include <freeswan.h>
|
||||
#include <libsha2/sha2.h>
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "mp_defs.h"
|
||||
#include "asn1.h"
|
||||
#include <asn1/oid.h>
|
||||
#include "log.h"
|
||||
#include "pkcs1.h"
|
||||
#include "md2.h"
|
||||
@@ -48,40 +50,38 @@ const struct fld RSA_private_field[] =
|
||||
{ "Coefficient", offsetof(RSA_private_key_t, qInv) },
|
||||
};
|
||||
|
||||
/* 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
|
||||
|
||||
|
||||
/*
|
||||
* forms the FreeS/WAN keyid from the public exponent e and modulus n
|
||||
/**
|
||||
* ASN.1 definition of a PKCS#1 RSA private key
|
||||
*/
|
||||
void
|
||||
form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
|
||||
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 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
#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
|
||||
|
||||
/**
|
||||
* Forms the FreeS/WAN keyid from the public exponent e and modulus n
|
||||
*/
|
||||
void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
|
||||
{
|
||||
/* eliminate leading zero bytes in modulus from ASN.1 coding */
|
||||
while (n.len > 1 && *n.ptr == 0x00)
|
||||
@@ -97,11 +97,10 @@ form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
|
||||
*keysize = n.len;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize an RSA_public_key_t object
|
||||
/**
|
||||
* Initialize an RSA_public_key_t object
|
||||
*/
|
||||
void
|
||||
init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
|
||||
void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
|
||||
{
|
||||
n_to_mpz(&rsa->e, e.ptr, e.len);
|
||||
n_to_mpz(&rsa->n, n.ptr, n.len);
|
||||
@@ -110,8 +109,7 @@ init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt)
|
||||
static void RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt)
|
||||
{
|
||||
const struct fld *p;
|
||||
|
||||
@@ -130,15 +128,15 @@ RSA_show_key_fields(RSA_private_key_t *k, int fieldcnt)
|
||||
}
|
||||
}
|
||||
|
||||
/* debugging info that compromises security! */
|
||||
void
|
||||
RSA_show_private_key(RSA_private_key_t *k)
|
||||
/**
|
||||
* debugging info that compromises security!
|
||||
*/
|
||||
void RSA_show_private_key(RSA_private_key_t *k)
|
||||
{
|
||||
RSA_show_key_fields(k, countof(RSA_private_field));
|
||||
}
|
||||
|
||||
void
|
||||
RSA_show_public_key(RSA_public_key_t *k)
|
||||
void RSA_show_public_key(RSA_public_key_t *k)
|
||||
{
|
||||
/* Kludge: pretend that it is a private key, but only display the
|
||||
* first two fields (which are the public key).
|
||||
@@ -148,8 +146,7 @@ RSA_show_public_key(RSA_public_key_t *k)
|
||||
}
|
||||
#endif
|
||||
|
||||
err_t
|
||||
RSA_private_key_sanity(RSA_private_key_t *k)
|
||||
err_t RSA_private_key_sanity(RSA_private_key_t *k)
|
||||
{
|
||||
/* note that the *last* error found is reported */
|
||||
err_t ugh = NULL;
|
||||
@@ -226,41 +223,36 @@ RSA_private_key_sanity(RSA_private_key_t *k)
|
||||
return ugh;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Check the equality of two RSA public keys
|
||||
*/
|
||||
bool
|
||||
same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b)
|
||||
bool same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b)
|
||||
{
|
||||
return a == b
|
||||
|| (a->k == b->k && mpz_cmp(&a->n, &b->n) == 0 && mpz_cmp(&a->e, &b->e) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Parses a PKCS#1 private key
|
||||
*/
|
||||
bool
|
||||
pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
|
||||
bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
|
||||
{
|
||||
err_t ugh = NULL;
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object, modulus, exp;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE, DBG_PRIVATE);
|
||||
|
||||
while (objectID < PKCS1_PRIV_KEY_ROOF) {
|
||||
|
||||
if (!extract_object(privkeyObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
int objectID;
|
||||
bool success = FALSE;
|
||||
|
||||
parser = asn1_parser_create(privkeyObjects, blob);
|
||||
parser->set_flags(parser, FALSE, TRUE);
|
||||
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (objectID == PKCS1_PRIV_KEY_VERSION)
|
||||
{
|
||||
if (object.len > 0 && *object.ptr != 0)
|
||||
{
|
||||
plog(" wrong PKCS#1 private key version");
|
||||
return FALSE;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
|
||||
@@ -276,18 +268,27 @@ pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
|
||||
else if (objectID == PKCS1_PRIV_KEY_PUB_EXP)
|
||||
exp = object;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
form_keyid(exp, modulus, key->pub.keyid, &key->pub.k);
|
||||
ugh = RSA_private_key_sanity(key);
|
||||
return (ugh == NULL);
|
||||
success = parser->success(parser);
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
|
||||
if (success)
|
||||
{
|
||||
err_t ugh;
|
||||
|
||||
form_keyid(exp, modulus, key->pub.keyid, &key->pub.k);
|
||||
ugh = RSA_private_key_sanity(key);
|
||||
success = (ugh == NULL);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* compute a digest over a binary blob
|
||||
/**
|
||||
* Compute a digest over a binary blob
|
||||
*/
|
||||
bool
|
||||
compute_digest(chunk_t tbs, int alg, chunk_t *digest)
|
||||
bool compute_digest(chunk_t tbs, int alg, chunk_t *digest)
|
||||
{
|
||||
switch (alg)
|
||||
{
|
||||
@@ -367,12 +368,11 @@ compute_digest(chunk_t tbs, int alg, chunk_t *digest)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* compute an RSA signature with PKCS#1 padding
|
||||
/**
|
||||
* Compute an RSA signature with PKCS#1 padding
|
||||
*/
|
||||
void
|
||||
sign_hash(const RSA_private_key_t *k, const u_char *hash_val, size_t hash_len
|
||||
, u_char *sig_val, size_t sig_len)
|
||||
void sign_hash(const RSA_private_key_t *k, const u_char *hash_val,
|
||||
size_t hash_len, u_char *sig_val, size_t sig_len)
|
||||
{
|
||||
chunk_t ch;
|
||||
mpz_t t1, t2;
|
||||
@@ -423,11 +423,10 @@ sign_hash(const RSA_private_key_t *k, const u_char *hash_val, size_t hash_len
|
||||
mpz_clear(t2);
|
||||
}
|
||||
|
||||
/*
|
||||
* encrypt data with an RSA public key after padding
|
||||
/**
|
||||
* Encrypt data with an RSA public key after padding
|
||||
*/
|
||||
chunk_t
|
||||
RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
|
||||
chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
|
||||
{
|
||||
u_char padded[RSA_MAX_OCTETS];
|
||||
u_char *pos = padded;
|
||||
@@ -485,11 +484,10 @@ RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* decrypt data with an RSA private key and remove padding
|
||||
/**
|
||||
* Decrypt data with an RSA private key and remove padding
|
||||
*/
|
||||
bool
|
||||
RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
|
||||
bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
|
||||
{
|
||||
chunk_t padded, plaintext;
|
||||
u_char *pos;
|
||||
@@ -551,12 +549,11 @@ RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* build signatureValue
|
||||
/**
|
||||
* Build signatureValue
|
||||
*/
|
||||
chunk_t
|
||||
pkcs1_build_signature(chunk_t tbs, int hash_alg, const RSA_private_key_t *key
|
||||
, bool bit_string)
|
||||
chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg,
|
||||
const RSA_private_key_t *key, bool bit_string)
|
||||
{
|
||||
|
||||
size_t siglen = key->pub.k;
|
||||
@@ -566,37 +563,27 @@ pkcs1_build_signature(chunk_t tbs, int hash_alg, const RSA_private_key_t *key
|
||||
chunk_t digestInfo, alg_id, signatureValue;
|
||||
u_char *pos;
|
||||
|
||||
switch (hash_alg)
|
||||
if (!compute_digest(tbs, hash_alg, &digest))
|
||||
{
|
||||
case OID_MD5:
|
||||
case OID_MD5_WITH_RSA:
|
||||
alg_id = ASN1_md5_id;
|
||||
break;
|
||||
case OID_SHA1:
|
||||
case OID_SHA1_WITH_RSA:
|
||||
alg_id = ASN1_sha1_id;
|
||||
break;
|
||||
default:
|
||||
return chunk_empty;
|
||||
}
|
||||
compute_digest(tbs, hash_alg, &digest);
|
||||
|
||||
/* according to PKCS#1 v2.1 digest must be packaged into
|
||||
* an ASN.1 structure for encryption
|
||||
*/
|
||||
digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm"
|
||||
, alg_id
|
||||
, asn1_algorithmIdentifier(hash_alg)
|
||||
, asn1_simple_object(ASN1_OCTET_STRING, digest));
|
||||
|
||||
/* generate the RSA signature */
|
||||
if (bit_string)
|
||||
{
|
||||
pos = build_asn1_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen);
|
||||
pos = asn1_build_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen);
|
||||
*pos++ = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = build_asn1_object(&signatureValue, ASN1_OCTET_STRING, siglen);
|
||||
pos = asn1_build_object(&signatureValue, ASN1_OCTET_STRING, siglen);
|
||||
}
|
||||
sign_hash(key, digestInfo.ptr, digestInfo.len, pos, siglen);
|
||||
free(digestInfo.ptr);
|
||||
@@ -604,11 +591,10 @@ pkcs1_build_signature(chunk_t tbs, int hash_alg, const RSA_private_key_t *key
|
||||
return signatureValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* build a DER-encoded PKCS#1 private key object
|
||||
/**
|
||||
* Build a DER-encoded PKCS#1 private key object
|
||||
*/
|
||||
chunk_t
|
||||
pkcs1_build_private_key(const RSA_private_key_t *key)
|
||||
chunk_t pkcs1_build_private_key(const RSA_private_key_t *key)
|
||||
{
|
||||
chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm"
|
||||
, ASN1_INTEGER_0
|
||||
@@ -627,44 +613,41 @@ pkcs1_build_private_key(const RSA_private_key_t *key)
|
||||
return pkcs1;
|
||||
}
|
||||
|
||||
/*
|
||||
* build a DER-encoded PKCS#1 public key object
|
||||
/**
|
||||
* Build a DER-encoded PKCS#1 public key object
|
||||
*/
|
||||
chunk_t
|
||||
pkcs1_build_public_key(const RSA_public_key_t *rsa)
|
||||
chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "mm"
|
||||
, asn1_integer_from_mpz(&rsa->n)
|
||||
, asn1_integer_from_mpz(&rsa->e));
|
||||
}
|
||||
|
||||
/*
|
||||
* build a DER-encoded publicKeyInfo object
|
||||
/**
|
||||
* Build a DER-encoded publicKeyInfo object
|
||||
*/
|
||||
chunk_t
|
||||
pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa)
|
||||
chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa)
|
||||
{
|
||||
chunk_t publicKey;
|
||||
chunk_t rawKey = pkcs1_build_public_key(rsa);
|
||||
u_char *pos;
|
||||
|
||||
u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING
|
||||
, 1 + rawKey.len);
|
||||
pos = asn1_build_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
|
||||
*pos++ = 0x00;
|
||||
mv_chunk(&pos, rawKey);
|
||||
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cm"
|
||||
, ASN1_rsaEncryption_id
|
||||
, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
|
||||
, publicKey);
|
||||
}
|
||||
void
|
||||
free_RSA_public_content(RSA_public_key_t *rsa)
|
||||
|
||||
void free_RSA_public_content(RSA_public_key_t *rsa)
|
||||
{
|
||||
mpz_clear(&rsa->n);
|
||||
mpz_clear(&rsa->e);
|
||||
}
|
||||
|
||||
void
|
||||
free_RSA_private_content(RSA_private_key_t *rsak)
|
||||
void free_RSA_private_content(RSA_private_key_t *rsak)
|
||||
{
|
||||
free_RSA_public_content(&rsak->pub);
|
||||
mpz_clear(&rsak->d);
|
||||
@@ -674,4 +657,3 @@ free_RSA_private_content(RSA_private_key_t *rsak)
|
||||
mpz_clear(&rsak->dQ);
|
||||
mpz_clear(&rsak->qInv);
|
||||
}
|
||||
|
||||
|
||||
+168
-151
@@ -22,10 +22,12 @@
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "defs.h"
|
||||
#include "asn1.h"
|
||||
#include <asn1/oid.h>
|
||||
#include "log.h"
|
||||
#include "x509.h"
|
||||
#include "certs.h"
|
||||
@@ -37,54 +39,55 @@ const contentInfo_t empty_contentInfo = {
|
||||
{ NULL, 0 } /* content */
|
||||
};
|
||||
|
||||
/* ASN.1 definition of the PKCS#7 ContentInfo type */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of the PKCS#7 ContentInfo type
|
||||
*/
|
||||
static const asn1Object_t contentInfoObjects[] = {
|
||||
{ 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
|
||||
{ 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
|
||||
{ 0, "contentInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "contentType", ASN1_OID, ASN1_BODY }, /* 1 */
|
||||
{ 1, "content", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_BODY }, /* 2 */
|
||||
{ 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define PKCS7_INFO_TYPE 1
|
||||
#define PKCS7_INFO_CONTENT 2
|
||||
#define PKCS7_INFO_ROOF 4
|
||||
|
||||
/* ASN.1 definition of the PKCS#7 signedData type */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of the PKCS#7 signedData type
|
||||
*/
|
||||
static const asn1Object_t signedDataObjects[] = {
|
||||
{ 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
|
||||
{ 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
|
||||
{ 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
|
||||
{ 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 6 */
|
||||
{ 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
|
||||
{ 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
|
||||
{ 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 9 */
|
||||
{ 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
|
||||
{ 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
|
||||
{ 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
|
||||
{ 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
|
||||
{ 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
|
||||
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
|
||||
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
|
||||
{ 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
|
||||
{ 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 19 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
|
||||
{ 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
|
||||
{ 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
|
||||
{ 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END } /* 25 */
|
||||
{ 0, "signedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "digestAlgorithms", ASN1_SET, ASN1_LOOP }, /* 2 */
|
||||
{ 2, "algorithm", ASN1_EOC, ASN1_RAW }, /* 3 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 4 */
|
||||
{ 1, "contentInfo", ASN1_EOC, ASN1_RAW }, /* 5 */
|
||||
{ 1, "certificates", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 6 */
|
||||
{ 2, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 7 */
|
||||
{ 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 8 */
|
||||
{ 1, "crls", ASN1_CONTEXT_C_1, ASN1_OPT |
|
||||
ASN1_LOOP }, /* 9 */
|
||||
{ 2, "crl", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
|
||||
{ 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 11 */
|
||||
{ 1, "signerInfos", ASN1_SET, ASN1_LOOP }, /* 12 */
|
||||
{ 2, "signerInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 14 */
|
||||
{ 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 15 */
|
||||
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 16 */
|
||||
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 17 */
|
||||
{ 3, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 18 */
|
||||
{ 3, "authenticatedAttributes", ASN1_CONTEXT_C_0, ASN1_OPT |
|
||||
ASN1_OBJ }, /* 19 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 20 */
|
||||
{ 3, "digestEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 21 */
|
||||
{ 3, "encryptedDigest", ASN1_OCTET_STRING, ASN1_BODY }, /* 22 */
|
||||
{ 3, "unauthenticatedAttributes", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 23 */
|
||||
{ 3, "end opt", ASN1_EOC, ASN1_END }, /* 24 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define PKCS7_DIGEST_ALG 3
|
||||
#define PKCS7_SIGNED_CONTENT_INFO 5
|
||||
#define PKCS7_SIGNED_CERT 7
|
||||
@@ -95,28 +98,28 @@ static const asn1Object_t signedDataObjects[] = {
|
||||
#define PKCS7_AUTH_ATTRIBUTES 19
|
||||
#define PKCS7_DIGEST_ENC_ALGORITHM 21
|
||||
#define PKCS7_ENCRYPTED_DIGEST 22
|
||||
#define PKCS7_SIGNED_ROOF 26
|
||||
|
||||
/* ASN.1 definition of the PKCS#7 envelopedData type */
|
||||
|
||||
/**
|
||||
* ASN.1 definition of the PKCS#7 envelopedData type
|
||||
*/
|
||||
static const asn1Object_t envelopedDataObjects[] = {
|
||||
{ 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */
|
||||
{ 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */
|
||||
{ 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
|
||||
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
|
||||
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */
|
||||
{ 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */
|
||||
{ 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
|
||||
{ 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
|
||||
{ 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */
|
||||
{ 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */
|
||||
{ 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY } /* 14 */
|
||||
{ 0, "envelopedData", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
|
||||
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
|
||||
{ 1, "recipientInfos", ASN1_SET, ASN1_LOOP }, /* 2 */
|
||||
{ 2, "recipientInfo", ASN1_SEQUENCE, ASN1_BODY }, /* 3 */
|
||||
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 4 */
|
||||
{ 3, "issuerAndSerialNumber", ASN1_SEQUENCE, ASN1_BODY }, /* 5 */
|
||||
{ 4, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
|
||||
{ 4, "serial", ASN1_INTEGER, ASN1_BODY }, /* 7 */
|
||||
{ 3, "encryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 8 */
|
||||
{ 3, "encryptedKey", ASN1_OCTET_STRING, ASN1_BODY }, /* 9 */
|
||||
{ 1, "end loop", ASN1_EOC, ASN1_END }, /* 10 */
|
||||
{ 1, "encryptedContentInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 11 */
|
||||
{ 2, "contentType", ASN1_OID, ASN1_BODY }, /* 12 */
|
||||
{ 2, "contentEncryptionAlgorithm", ASN1_EOC, ASN1_RAW }, /* 13 */
|
||||
{ 2, "encryptedContent", ASN1_CONTEXT_S_0, ASN1_BODY }, /* 14 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define PKCS7_ENVELOPED_VERSION 1
|
||||
#define PKCS7_RECIPIENT_INFO_VERSION 4
|
||||
#define PKCS7_ISSUER 6
|
||||
@@ -128,7 +131,9 @@ static const asn1Object_t envelopedDataObjects[] = {
|
||||
#define PKCS7_ENCRYPTED_CONTENT 14
|
||||
#define PKCS7_ENVELOPED_ROOF 15
|
||||
|
||||
/* PKCS7 contentInfo OIDs */
|
||||
/**
|
||||
* PKCS7 contentInfo OIDs
|
||||
*/
|
||||
|
||||
static u_char ASN1_pkcs7_data_oid_str[] = {
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01
|
||||
@@ -167,7 +172,9 @@ static const chunk_t ASN1_pkcs7_digested_data_oid =
|
||||
static const chunk_t ASN1_pkcs7_encrypted_data_oid =
|
||||
chunk_from_buf(ASN1_pkcs7_encrypted_data_oid_str);
|
||||
|
||||
/* 3DES and DES encryption OIDs */
|
||||
/**
|
||||
* 3DES and DES encryption OIDs
|
||||
*/
|
||||
|
||||
static u_char ASN1_3des_ede_cbc_oid_str[] = {
|
||||
0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07
|
||||
@@ -182,7 +189,9 @@ static const chunk_t ASN1_3des_ede_cbc_oid =
|
||||
static const chunk_t ASN1_des_cbc_oid =
|
||||
chunk_from_buf(ASN1_des_cbc_oid_str);
|
||||
|
||||
/* PKCS#7 attribute type OIDs */
|
||||
/**
|
||||
* PKCS#7 attribute type OIDs
|
||||
*/
|
||||
|
||||
static u_char ASN1_contentType_oid_str[] = {
|
||||
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x03
|
||||
@@ -197,24 +206,21 @@ static const chunk_t ASN1_contentType_oid =
|
||||
static const chunk_t ASN1_messageDigest_oid =
|
||||
chunk_from_buf(ASN1_messageDigest_oid_str);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Parse PKCS#7 ContentInfo object
|
||||
*/
|
||||
bool
|
||||
pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo)
|
||||
bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
bool success = FALSE;
|
||||
|
||||
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(contentInfoObjects, blob);
|
||||
parser->set_top_level(parser, level0);
|
||||
|
||||
while (objectID < PKCS7_INFO_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(contentInfoObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
if (objectID == PKCS7_INFO_TYPE)
|
||||
{
|
||||
cInfo->type = asn1_known_oid(object);
|
||||
@@ -222,57 +228,60 @@ pkcs7_parse_contentInfo(chunk_t blob, u_int level0, contentInfo_t *cInfo)
|
||||
|| cInfo->type > OID_PKCS7_ENCRYPTED_DATA)
|
||||
{
|
||||
plog("unknown pkcs7 content type");
|
||||
return FALSE;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else if (objectID == PKCS7_INFO_CONTENT)
|
||||
{
|
||||
cInfo->content = object;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
success = parser->success(parser);
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Parse a PKCS#7 signedData object
|
||||
*/
|
||||
bool
|
||||
pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
|
||||
, chunk_t *attributes, const x509cert_t *cacert)
|
||||
bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert,
|
||||
chunk_t *attributes, const x509cert_t *cacert)
|
||||
{
|
||||
u_char buf[BUF_LEN];
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int digest_alg = OID_UNKNOWN;
|
||||
int enc_alg = OID_UNKNOWN;
|
||||
int signerInfos = 0;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
bool success = FALSE;
|
||||
|
||||
contentInfo_t cInfo = empty_contentInfo;
|
||||
chunk_t encrypted_digest = chunk_empty;
|
||||
|
||||
if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
|
||||
{
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
if (cInfo.type != OID_PKCS7_SIGNED_DATA)
|
||||
{
|
||||
plog("pkcs7 content type is not signedData");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(signedDataObjects, blob);
|
||||
parser->set_top_level(parser, 2);
|
||||
|
||||
while (objectID < PKCS7_SIGNED_ROOF)
|
||||
{
|
||||
if (!extract_object(signedDataObjects, &objectID, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
u_int level = parser->get_level(parser);
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case PKCS7_DIGEST_ALG:
|
||||
digest_alg = parse_algorithmIdentifier(object, level, NULL);
|
||||
digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case PKCS7_SIGNED_CONTENT_INFO:
|
||||
if (data != NULL)
|
||||
@@ -322,15 +331,20 @@ pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
|
||||
}
|
||||
break;
|
||||
case PKCS7_DIGEST_ALGORITHM:
|
||||
digest_alg = parse_algorithmIdentifier(object, level, NULL);
|
||||
digest_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case PKCS7_DIGEST_ENC_ALGORITHM:
|
||||
enc_alg = parse_algorithmIdentifier(object, level, NULL);
|
||||
enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
break;
|
||||
case PKCS7_ENCRYPTED_DIGEST:
|
||||
encrypted_digest = object;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
success = parser->success(parser);
|
||||
parser->destroy(parser);
|
||||
if (!success)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* check the signature only if a cacert is available */
|
||||
@@ -367,44 +381,45 @@ pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Parse a PKCS#7 envelopedData object
|
||||
*/
|
||||
bool
|
||||
pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
, chunk_t serialNumber, const RSA_private_key_t *key)
|
||||
bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
|
||||
chunk_t serialNumber,
|
||||
const RSA_private_key_t *key)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
chunk_t iv = chunk_empty;
|
||||
chunk_t symmetric_key = chunk_empty;
|
||||
chunk_t encrypted_content = chunk_empty;
|
||||
|
||||
u_char buf[BUF_LEN];
|
||||
u_int level;
|
||||
u_int total_keys = 3;
|
||||
int enc_alg = OID_UNKNOWN;
|
||||
int content_enc_alg = OID_UNKNOWN;
|
||||
int objectID = 0;
|
||||
int objectID;
|
||||
bool success = FALSE;
|
||||
|
||||
contentInfo_t cInfo = empty_contentInfo;
|
||||
*data = chunk_empty;
|
||||
|
||||
if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
|
||||
goto failed;
|
||||
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
if (cInfo.type != OID_PKCS7_ENVELOPED_DATA)
|
||||
{
|
||||
plog("pkcs7 content type is not envelopedData");
|
||||
return FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
asn1_init(&ctx, cInfo.content, 2, FALSE, DBG_RAW);
|
||||
parser = asn1_parser_create(envelopedDataObjects, cInfo.content);
|
||||
parser->set_top_level(parser, 2);
|
||||
|
||||
while (objectID < PKCS7_ENVELOPED_ROOF)
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(envelopedDataObjects, &objectID, &object, &level, &ctx))
|
||||
goto failed;
|
||||
u_int level = parser->get_level(parser);
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
@@ -412,14 +427,14 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
if (*object.ptr != 0)
|
||||
{
|
||||
plog("envelopedData version is not 0");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case PKCS7_RECIPIENT_INFO_VERSION:
|
||||
if (*object.ptr != 0)
|
||||
{
|
||||
plog("recipient info version is not 0");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case PKCS7_ISSUER:
|
||||
@@ -432,22 +447,22 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
if (!chunk_equals(serialNumber, object))
|
||||
{
|
||||
plog("serial numbers do not match");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case PKCS7_ENCRYPTION_ALG:
|
||||
enc_alg = parse_algorithmIdentifier(object, level, NULL);
|
||||
enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
|
||||
if (enc_alg != OID_RSA_ENCRYPTION)
|
||||
{
|
||||
plog("only rsa encryption supported");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case PKCS7_ENCRYPTED_KEY:
|
||||
if (!RSA_decrypt(key, object, &symmetric_key))
|
||||
{
|
||||
plog("symmetric key could not be decrypted with rsa");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
DBG(DBG_PRIVATE,
|
||||
DBG_dump_chunk("symmetric key :", symmetric_key)
|
||||
@@ -457,11 +472,11 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
if (asn1_known_oid(object) != OID_PKCS7_DATA)
|
||||
{
|
||||
plog("encrypted content not of type pkcs7 data");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case PKCS7_CONTENT_ENC_ALGORITHM:
|
||||
content_enc_alg = parse_algorithmIdentifier(object, level, &iv);
|
||||
content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv);
|
||||
|
||||
switch (content_enc_alg)
|
||||
{
|
||||
@@ -473,29 +488,33 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
break;
|
||||
default:
|
||||
plog("Only DES and 3DES supported for symmetric encryption");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
if (symmetric_key.len != (total_keys * DES_CBC_BLOCK_SIZE))
|
||||
{
|
||||
plog("key length is not %d",(total_keys * DES_CBC_BLOCK_SIZE));
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
if (!parse_asn1_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV"))
|
||||
if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV"))
|
||||
{
|
||||
plog("IV could not be parsed");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
if (iv.len != DES_CBC_BLOCK_SIZE)
|
||||
{
|
||||
plog("IV has wrong length");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
break;
|
||||
case PKCS7_ENCRYPTED_CONTENT:
|
||||
encrypted_content = object;
|
||||
break;
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
;
|
||||
if (!parser->success(parser))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* decrypt the content */
|
||||
@@ -512,7 +531,7 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
if (des_set_key(&des_key[i], key_s[i]))
|
||||
{
|
||||
plog("des key schedule failed");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +565,7 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
if (padding > data->len)
|
||||
{
|
||||
plog("padding greater than data length");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
data->len -= padding;
|
||||
|
||||
@@ -555,17 +574,19 @@ pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data
|
||||
if (*pos-- != pattern)
|
||||
{
|
||||
plog("wrong padding pattern");
|
||||
goto failed;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
chunk_clear(&symmetric_key);
|
||||
return TRUE;
|
||||
success = TRUE;
|
||||
|
||||
failed:
|
||||
end:
|
||||
chunk_clear(&symmetric_key);
|
||||
free(data->ptr);
|
||||
return FALSE;
|
||||
if (!success)
|
||||
{
|
||||
free(data->ptr);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,8 +594,7 @@ failed:
|
||||
*
|
||||
* @return ASN.1 encoded contentType attribute
|
||||
*/
|
||||
chunk_t
|
||||
pkcs7_contentType_attribute(void)
|
||||
chunk_t pkcs7_contentType_attribute(void)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cm"
|
||||
, ASN1_contentType_oid
|
||||
@@ -590,8 +610,7 @@ pkcs7_contentType_attribute(void)
|
||||
* @return ASN.1 encoded messageDigest attribute
|
||||
*
|
||||
*/
|
||||
chunk_t
|
||||
pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
|
||||
chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
|
||||
{
|
||||
u_char digest_buf[MAX_DIGEST_LEN];
|
||||
chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
|
||||
@@ -605,11 +624,11 @@ pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
|
||||
)
|
||||
);
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* build a DER-encoded contentInfo object
|
||||
*/
|
||||
static chunk_t
|
||||
pkcs7_build_contentInfo(contentInfo_t *cInfo)
|
||||
static chunk_t pkcs7_build_contentInfo(contentInfo_t *cInfo)
|
||||
{
|
||||
chunk_t content_type;
|
||||
|
||||
@@ -648,23 +667,22 @@ pkcs7_build_contentInfo(contentInfo_t *cInfo)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* build issuerAndSerialNumber object
|
||||
*/
|
||||
chunk_t
|
||||
pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert)
|
||||
chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert)
|
||||
{
|
||||
return asn1_wrap(ASN1_SEQUENCE, "cm"
|
||||
, cert->issuer
|
||||
, asn1_simple_object(ASN1_INTEGER, cert->serialNumber));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* create a signed pkcs7 contentInfo object
|
||||
*/
|
||||
chunk_t
|
||||
pkcs7_build_signedData(chunk_t data, chunk_t attributes, const x509cert_t *cert
|
||||
, int digest_alg, const RSA_private_key_t *key)
|
||||
chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
|
||||
const x509cert_t *cert, int digest_alg,
|
||||
const RSA_private_key_t *key)
|
||||
{
|
||||
contentInfo_t pkcs7Data, signedData;
|
||||
chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
|
||||
@@ -690,7 +708,7 @@ pkcs7_build_signedData(chunk_t data, chunk_t attributes, const x509cert_t *cert
|
||||
, pkcs7_build_issuerAndSerialNumber(cert)
|
||||
, digestAlgorithm
|
||||
, authenticatedAttributes
|
||||
, ASN1_rsaEncryption_id
|
||||
, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
|
||||
, encryptedDigest);
|
||||
|
||||
pkcs7Data.type = OID_PKCS7_DATA;
|
||||
@@ -715,11 +733,10 @@ pkcs7_build_signedData(chunk_t data, chunk_t attributes, const x509cert_t *cert
|
||||
return cInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* create a symmetrically encrypted pkcs7 contentInfo object
|
||||
*/
|
||||
chunk_t
|
||||
pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int cipher)
|
||||
chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int cipher)
|
||||
{
|
||||
bool des_check_key_save;
|
||||
des_key_schedule ks[3];
|
||||
@@ -833,7 +850,7 @@ pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int cipher)
|
||||
chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
|
||||
, ASN1_INTEGER_0
|
||||
, pkcs7_build_issuerAndSerialNumber(cert)
|
||||
, ASN1_rsaEncryption_id
|
||||
, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
|
||||
, encryptedKey);
|
||||
|
||||
chunk_t cInfo;
|
||||
|
||||
+504
-571
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
||||
#ifndef _X509_H
|
||||
#define _X509_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "pkcs1.h"
|
||||
#include "id.h"
|
||||
|
||||
|
||||
@@ -18,15 +18,16 @@ INCLUDES = \
|
||||
AM_CFLAGS = \
|
||||
-DIPSEC_CONFDIR=\"${confdir}\" \
|
||||
-DSTRONGSWAN_CONF=\"${strongswan_conf}\" \
|
||||
-DDEBUG -DNO_PLUTO
|
||||
-DDEBUG -DNO_PLUTO \
|
||||
-Wformat=0
|
||||
|
||||
LIBFREESWANBUILDDIR=$(top_builddir)/src/libfreeswan
|
||||
LIBCRYPTOBUILDDIR=$(top_builddir)/src/libcrypto
|
||||
|
||||
scepclient_LDADD = \
|
||||
asn1.o ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o \
|
||||
lex.o library.o md2.o md5.o mp_defs.o ocsp.o pem.o pgp.o pkcs1.o \
|
||||
pkcs7.o rnd.o sha1.o smartcard.o x509.o \
|
||||
ca.o crl.o certs.o constants.o defs.o fetch.o id.o keys.o lex.o library.o \
|
||||
md2.o md5.o mp_defs.o ocsp.o pem.o pgp.o pkcs1.o pkcs7.o rnd.o sha1.o \
|
||||
smartcard.o x509.o \
|
||||
$(LIBSTRONGSWANDIR)/libstrongswan-lite.la \
|
||||
$(LIBFREESWANBUILDDIR)/libfreeswan.a \
|
||||
$(LIBCRYPTOBUILDDIR)/libcrypto.a \
|
||||
@@ -51,9 +52,6 @@ endif
|
||||
|
||||
dist_man_MANS = scepclient.8
|
||||
|
||||
asn1.o : $(PLUTODIR)/asn1.c $(PLUTODIR)/asn1.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
ca.o : $(PLUTODIR)/ca.c $(PLUTODIR)/ca.h
|
||||
$(COMPILE) $(INCLUDES) -c -o $@ $<
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <freeswan.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#include "../pluto/constants.h"
|
||||
#include "../pluto/defs.h"
|
||||
#include "../pluto/asn1.h"
|
||||
#include "../pluto/pkcs1.h"
|
||||
#include "../pluto/log.h"
|
||||
#include "../pluto/x509.h"
|
||||
@@ -133,7 +133,7 @@ build_req_info_attributes(pkcs10_t* pkcs10)
|
||||
|
||||
if (pkcs10->challengePassword.len > 0)
|
||||
{
|
||||
asn1_t type = is_printablestring(pkcs10->challengePassword)
|
||||
asn1_t type = asn1_is_printablestring(pkcs10->challengePassword)
|
||||
? ASN1_PRINTABLESTRING : ASN1_T61STRING;
|
||||
|
||||
challengePassword = asn1_wrap(ASN1_SEQUENCE, "cm"
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
#include "../pluto/defs.h"
|
||||
#include "../pluto/mp_defs.h"
|
||||
#include "../pluto/log.h"
|
||||
#include "../pluto/asn1.h"
|
||||
#include "../pluto/pkcs1.h"
|
||||
|
||||
#include "rsakey.h"
|
||||
|
||||
+55
-55
@@ -24,6 +24,9 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <freeswan.h>
|
||||
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/asn1_parser.h>
|
||||
#include <asn1/oid.h>
|
||||
|
||||
#ifdef LIBCURL
|
||||
@@ -33,7 +36,6 @@
|
||||
#include "../pluto/constants.h"
|
||||
#include "../pluto/defs.h"
|
||||
#include "../pluto/rnd.h"
|
||||
#include "../pluto/asn1.h"
|
||||
#include "../pluto/pkcs1.h"
|
||||
#include "../pluto/fetch.h"
|
||||
#include "../pluto/log.h"
|
||||
@@ -62,62 +64,60 @@ static const chunk_t ASN1_transId_oid =
|
||||
static const char *pkiStatus_values[] = { "0", "2", "3" };
|
||||
|
||||
static const char *pkiStatus_names[] = {
|
||||
"SUCCESS",
|
||||
"FAILURE",
|
||||
"PENDING",
|
||||
"UNKNOWN"
|
||||
"SUCCESS",
|
||||
"FAILURE",
|
||||
"PENDING",
|
||||
"UNKNOWN"
|
||||
};
|
||||
|
||||
static const char *msgType_values[] = { "3", "19", "20", "21", "22" };
|
||||
|
||||
static const char *msgType_names[] = {
|
||||
"CertRep",
|
||||
"PKCSReq",
|
||||
"GetCertInitial",
|
||||
"GetCert",
|
||||
"GetCRL",
|
||||
"Unknown"
|
||||
"CertRep",
|
||||
"PKCSReq",
|
||||
"GetCertInitial",
|
||||
"GetCert",
|
||||
"GetCRL",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
static const char *failInfo_reasons[] = {
|
||||
"badAlg - unrecognized or unsupported algorithm identifier",
|
||||
"badMessageCheck - integrity check failed",
|
||||
"badRequest - transaction not permitted or supported",
|
||||
"badTime - Message time field was not sufficiently close to the system time",
|
||||
"badCertId - No certificate could be identified matching the provided criteria"
|
||||
"badAlg - unrecognized or unsupported algorithm identifier",
|
||||
"badMessageCheck - integrity check failed",
|
||||
"badRequest - transaction not permitted or supported",
|
||||
"badTime - Message time field was not sufficiently close to the system time",
|
||||
"badCertId - No certificate could be identified matching the provided criteria"
|
||||
};
|
||||
|
||||
const scep_attributes_t empty_scep_attributes = {
|
||||
SCEP_Unknown_MSG , /* msgType */
|
||||
SCEP_UNKNOWN , /* pkiStatus */
|
||||
SCEP_unknown_REASON, /* failInfo */
|
||||
{ NULL, 0 } , /* transID */
|
||||
{ NULL, 0 } , /* senderNonce */
|
||||
{ NULL, 0 } , /* recipientNonce */
|
||||
SCEP_Unknown_MSG , /* msgType */
|
||||
SCEP_UNKNOWN , /* pkiStatus */
|
||||
SCEP_unknown_REASON, /* failInfo */
|
||||
{ NULL, 0 } , /* transID */
|
||||
{ NULL, 0 } , /* senderNonce */
|
||||
{ NULL, 0 } , /* recipientNonce */
|
||||
};
|
||||
|
||||
/* ASN.1 definition of the X.501 atttribute type */
|
||||
|
||||
static const asn1Object_t attributesObjects[] = {
|
||||
{ 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
|
||||
{ 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
||||
{ 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
|
||||
{ 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
|
||||
{ 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
|
||||
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 0, "attributes", ASN1_SET, ASN1_LOOP }, /* 0 */
|
||||
{ 1, "attribute", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */
|
||||
{ 2, "type", ASN1_OID, ASN1_BODY }, /* 2 */
|
||||
{ 2, "values", ASN1_SET, ASN1_LOOP }, /* 3 */
|
||||
{ 3, "value", ASN1_EOC, ASN1_RAW }, /* 4 */
|
||||
{ 2, "end loop", ASN1_EOC, ASN1_END }, /* 5 */
|
||||
{ 0, "end loop", ASN1_EOC, ASN1_END }, /* 6 */
|
||||
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
|
||||
};
|
||||
|
||||
#define ATTRIBUTE_OBJ_TYPE 2
|
||||
#define ATTRIBUTE_OBJ_VALUE 4
|
||||
#define ATTRIBUTE_OBJ_ROOF 7
|
||||
|
||||
/*
|
||||
* extract and store an attribute
|
||||
/**
|
||||
* Extract and store an attribute
|
||||
*/
|
||||
static bool
|
||||
extract_attribute(int oid, chunk_t object, u_int level
|
||||
, scep_attributes_t *attrs)
|
||||
static bool extract_attribute(int oid, chunk_t object, u_int level,
|
||||
scep_attributes_t *attrs)
|
||||
{
|
||||
asn1_t type = ASN1_EOC;
|
||||
const char *name = "none";
|
||||
@@ -167,7 +167,7 @@ extract_attribute(int oid, chunk_t object, u_int level
|
||||
if (type == ASN1_EOC)
|
||||
return TRUE;
|
||||
|
||||
if (!parse_asn1_simple_object(&object, type, level+1, name))
|
||||
if (!asn1_parse_simple_object(&object, type, level+1, name))
|
||||
return FALSE;
|
||||
|
||||
switch (oid)
|
||||
@@ -227,41 +227,41 @@ extract_attribute(int oid, chunk_t object, u_int level
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* parse X.501 attributes
|
||||
/**
|
||||
* Parse X.501 attributes
|
||||
*/
|
||||
bool
|
||||
parse_attributes(chunk_t blob, scep_attributes_t *attrs)
|
||||
bool parse_attributes(chunk_t blob, scep_attributes_t *attrs)
|
||||
{
|
||||
asn1_ctx_t ctx;
|
||||
asn1_parser_t *parser;
|
||||
chunk_t object;
|
||||
u_int level;
|
||||
int oid = OID_UNKNOWN;
|
||||
int objectID = 0;
|
||||
|
||||
asn1_init(&ctx, blob, 0, FALSE, DBG_RAW);
|
||||
int objectID;
|
||||
bool success = FALSE;
|
||||
|
||||
parser = asn1_parser_create(attributesObjects, blob);
|
||||
DBG(DBG_CONTROL | DBG_PARSING,
|
||||
DBG_log("parsing attributes")
|
||||
)
|
||||
while (objectID < ATTRIBUTE_OBJ_ROOF)
|
||||
|
||||
while (parser->iterate(parser, &objectID, &object))
|
||||
{
|
||||
if (!extract_object(attributesObjects, &objectID
|
||||
, &object, &level, &ctx))
|
||||
return FALSE;
|
||||
|
||||
switch (objectID)
|
||||
{
|
||||
case ATTRIBUTE_OBJ_TYPE:
|
||||
oid = asn1_known_oid(object);
|
||||
break;
|
||||
case ATTRIBUTE_OBJ_VALUE:
|
||||
if (!extract_attribute(oid, object, level, attrs))
|
||||
return FALSE;
|
||||
if (!extract_attribute(oid, object, parser->get_level(parser), attrs))
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
objectID++;
|
||||
}
|
||||
return TRUE;
|
||||
success = parser->success(parser);
|
||||
|
||||
end:
|
||||
parser->destroy(parser);
|
||||
return success;
|
||||
}
|
||||
|
||||
/* generates a unique fingerprint of the pkcs10 request
|
||||
|
||||
+12
-12
@@ -38,13 +38,13 @@
|
||||
#include <freeswan.h>
|
||||
#include <library.h>
|
||||
#include <debug.h>
|
||||
#include <asn1/asn1.h>
|
||||
#include <asn1/oid.h>
|
||||
#include <utils/optionsfrom.h>
|
||||
|
||||
#include "../pluto/constants.h"
|
||||
#include "../pluto/defs.h"
|
||||
#include "../pluto/log.h"
|
||||
#include "../pluto/asn1.h"
|
||||
#include "../pluto/pkcs1.h"
|
||||
#include "../pluto/pkcs7.h"
|
||||
#include "../pluto/certs.h"
|
||||
@@ -604,7 +604,7 @@ int main(int argc, char **argv)
|
||||
usage("date format must be YYMMDDHHMMSSZ");
|
||||
{
|
||||
chunk_t date = { optarg, 13 };
|
||||
notBefore = asn1totime(&date, ASN1_UTCTIME);
|
||||
notBefore = asn1_to_time(&date, ASN1_UTCTIME);
|
||||
}
|
||||
continue;
|
||||
|
||||
@@ -613,7 +613,7 @@ int main(int argc, char **argv)
|
||||
usage("date format must be YYMMDDHHMMSSZ");
|
||||
{
|
||||
chunk_t date = { optarg, 13 };
|
||||
notAfter = asn1totime(&date, ASN1_UTCTIME);
|
||||
notAfter = asn1_to_time(&date, ASN1_UTCTIME);
|
||||
}
|
||||
continue;
|
||||
|
||||
@@ -800,7 +800,7 @@ int main(int argc, char **argv)
|
||||
if (filetype_in & PKCS1) /* load an RSA key pair from file */
|
||||
{
|
||||
prompt_pass_t pass = { "", FALSE, STDIN_FILENO };
|
||||
const char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
|
||||
char *path = concatenate_paths(PRIVATE_KEY_PATH, file_in_pkcs1);
|
||||
|
||||
ugh = load_rsa_private_key(path, &pass, private_key);
|
||||
}
|
||||
@@ -877,9 +877,9 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_out & PKCS10)
|
||||
{
|
||||
const char *path = concatenate_paths(REQ_PATH, file_out_pkcs10);
|
||||
char *path = concatenate_paths(REQ_PATH, file_out_pkcs10);
|
||||
|
||||
if (!chunk_write(pkcs10->request,path, "pkcs10", 0022, force))
|
||||
if (!chunk_write(pkcs10->request, path, "pkcs10", 0022, force))
|
||||
exit_scepclient("could not write pkcs10 file '%s'", path);
|
||||
|
||||
filetype_out &= ~PKCS10; /* delete PKCS10 flag */
|
||||
@@ -895,7 +895,7 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_out & PKCS1)
|
||||
{
|
||||
const char *path = concatenate_paths(PRIVATE_KEY_PATH, file_out_pkcs1);
|
||||
char *path = concatenate_paths(PRIVATE_KEY_PATH, file_out_pkcs1);
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("building pkcs1 object:")
|
||||
@@ -938,7 +938,7 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_out & CERT_SELF)
|
||||
{
|
||||
const char *path = concatenate_paths(HOST_CERT_PATH, file_out_cert_self);
|
||||
char *path = concatenate_paths(HOST_CERT_PATH, file_out_cert_self);
|
||||
|
||||
if (!chunk_write(x509_signer->certificate, path, "self-signed cert", 0022, force))
|
||||
exit_scepclient("could not write self-signed cert file '%s'", path);
|
||||
@@ -955,7 +955,7 @@ int main(int argc, char **argv)
|
||||
* load ca encryption certificate
|
||||
*/
|
||||
{
|
||||
const char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_enc);
|
||||
char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_enc);
|
||||
cert_t cert;
|
||||
|
||||
if (!load_cert(path, "encryption cacert", &cert))
|
||||
@@ -994,7 +994,7 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_out & PKCS7)
|
||||
{
|
||||
const char *path = concatenate_paths(REQ_PATH, file_out_pkcs7);
|
||||
char *path = concatenate_paths(REQ_PATH, file_out_pkcs7);
|
||||
|
||||
if (!chunk_write(pkcs7, path, "pkcs7 encrypted request", 0022, force))
|
||||
exit_scepclient("could not write pkcs7 file '%s'", path);
|
||||
@@ -1012,7 +1012,7 @@ int main(int argc, char **argv)
|
||||
*/
|
||||
if (filetype_out & CERT)
|
||||
{
|
||||
const char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig);
|
||||
char *path = concatenate_paths(CA_CERT_PATH, file_in_cacert_sig);
|
||||
cert_t cert;
|
||||
time_t poll_start;
|
||||
|
||||
@@ -1094,7 +1094,7 @@ int main(int argc, char **argv)
|
||||
envelopedData = data.content;
|
||||
|
||||
if (data.type != OID_PKCS7_DATA
|
||||
|| !parse_asn1_simple_object(&envelopedData, ASN1_OCTET_STRING, 0, "data"))
|
||||
|| !asn1_parse_simple_object(&envelopedData, ASN1_OCTET_STRING, 0, "data"))
|
||||
{
|
||||
exit_scepclient("contentInfo is not of type 'data'");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user