Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: vpnc: devel

[PATCH v3] modularize certificate code + gnutls support

 

 

vpnc devel RSS feed   Index | Next | Previous | View Threaded


dcbw at redhat

Aug 12, 2009, 11:34 AM

Post #1 of 5 (1043 views)
Permalink
[PATCH v3] modularize certificate code + gnutls support

vpnc currently requires openssl to provide the hybrid auth mode. That's
not ideal, since vpnc doesn't not include the OpenSSL exception in its
license, meaning many distributions cannot ship a hybrid-auth-enabled
vpnc.

This patch splits out the certificate handing functions into a more
modular framework, and adds a gnutls implementation of certificate
handling bits, including testcases to ensure things work as expected.
Hybrid-auth with gnutls is the default mode now, since vpnc has no
licensing problem with gnutls. That means everyone gets hybrid FTW.

Patch against current trunk. Also available here:

http://people.redhat.com/dcbw/vpnc-hybrid-gnutls.patch

Mostly by Dan Williams <dcbw [at] redhat>
gnutls padding fixes by Laurent Goujon <laurent.goujon [at] online>

---
diff --git a/Makefile b/Makefile
index 816c313..28b4266 100644
--- a/Makefile
+++ b/Makefile
@@ -27,16 +27,8 @@ SBINDIR=$(PREFIX)/sbin
MANDIR=$(PREFIX)/share/man
DOCDIR=$(PREFIX)/share/doc/vpnc

-SRCS = sysdep.c vpnc-debug.c isakmp-pkt.c tunip.c config.c dh.c math_group.c supp.c decrypt-utils.c
-BINS = vpnc cisco-decrypt
-OBJS = $(addsuffix .o,$(basename $(SRCS)))
-BINOBJS = $(addsuffix .o,$(BINS))
-BINSRCS = $(addsuffix .c,$(BINS))
-VERSION := $(shell sh mk-version)
-RELEASE_VERSION := $(shell cat VERSION)
-
# The license of vpnc (Gpl >= 2) is quite likely incompatible with the
-# openssl license. Openssl is currently used to provide certificate
+# openssl license. Openssl is one possible library used to provide certificate
# support for vpnc (hybrid only).
# While it is OK for users to build their own binaries linking in openssl
# with vpnc and even providing dynamically linked binaries it is probably
@@ -47,16 +39,34 @@ RELEASE_VERSION := $(shell cat VERSION)

# Comment this in to obtain a binary with certificate support which is
# GPL incompliant though.
-#OPENSSL_GPL_VIOLATION = -DOPENSSL_GPL_VIOLATION
-#OPENSSLLIBS = -lcrypto
+#OPENSSL_GPL_VIOLATION=yes
+
+CRYPTO_LDADD = $(shell libgnutls-config --libs)
+CRYPTO_CFLAGS = $(shell libgnutls-config --cflags) -DCRYPTO_GNUTLS
+CRYPTO_SRCS = crypto-gnutls.c
+
+ifeq ($(OPENSSL_GPL_VIOLATION), yes)
+CRYPTO_LDADD = -lcrypto
+CRYPTO_CFLAGS = -DOPENSSL_GPL_VIOLATION -DCRYPTO_OPENSSL
+CRYPTO_SRCS = crypto-openssl.c
+endif
+
+SRCS = sysdep.c vpnc-debug.c isakmp-pkt.c tunip.c config.c dh.c math_group.c supp.c decrypt-utils.c crypto.c $(CRYPTO_SRCS)
+BINS = vpnc cisco-decrypt test-crypto
+OBJS = $(addsuffix .o,$(basename $(SRCS)))
+CRYPTO_OBJS = $(addsuffix .o,$(basename $(CRYPTO_SRCS)))
+BINOBJS = $(addsuffix .o,$(BINS))
+BINSRCS = $(addsuffix .c,$(BINS))
+VERSION := $(shell sh mk-version)
+RELEASE_VERSION := $(shell cat VERSION)

CC=gcc
CFLAGS ?= -O3 -g
CFLAGS += -W -Wall -Wmissing-declarations -Wwrite-strings
-CFLAGS += $(shell libgcrypt-config --cflags)
-CPPFLAGS += -DVERSION=\"$(VERSION)\" $(OPENSSL_GPL_VIOLATION)
+CFLAGS += $(shell libgcrypt-config --cflags) $(CRYPTO_CFLAGS)
+CPPFLAGS += -DVERSION=\"$(VERSION)\"
LDFLAGS ?= -g
-LDFLAGS += $(shell libgcrypt-config --libs) $(OPENSSLLIBS)
+LDFLAGS += $(shell libgcrypt-config --libs) $(CRYPTO_LDADD)

ifeq ($(shell uname -s), SunOS)
LDFLAGS += -lnsl -lresolv -lsocket
@@ -80,6 +90,9 @@ vpnc-script : vpnc-script.in
cisco-decrypt : cisco-decrypt.o decrypt-utils.o
$(CC) -o $@ $^ $(LDFLAGS)

+test-crypto : test-crypto.o crypto.o $(CRYPTO_OBJS)
+ $(CC) -o $@ $^ $(LDFLAGS)
+
.depend: $(SRCS) $(BINSRCS)
$(CC) -MM $(SRCS) $(BINSRCS) $(CFLAGS) $(CPPFLAGS) > $@

@@ -103,6 +116,10 @@ vpnc-%.tar.gz :
tar -czf ../$@ vpnc-$*
rm -rf vpnc-$*

+test : all
+ ./test-crypto /etc/pki/tls/cert.pem test/cert0.pem test/cert1.pem test/cert2.pem test/root.pem
+ ./test-crypto /etc/pki/tls/cert.pem test/cert0.crt test/cert1.crt test/cert2.crt test/root.crt
+
dist : VERSION vpnc.8 vpnc-$(RELEASE_VERSION).tar.gz

clean :
diff --git a/config.c b/config.c
index 9e82a99..48817af 100644
--- a/config.c
+++ b/config.c
@@ -424,7 +424,7 @@ static const struct config_names_s {
"Authentication mode:\n"
" * psk: pre-shared key (default)\n"
" * cert: server + client certificate (not implemented yet)\n"
- " * hybrid: server certificate + xauth (if built with openssl support)\n",
+ " * hybrid: server certificate + xauth (if built with certificate support)\n",
config_def_auth_mode
}, {
CONFIG_CA_FILE, 1, 1,
@@ -581,10 +581,10 @@ static void print_version(void)
"Public License. For more information about these matters, see the files\n"
"named COPYING.\n");
#ifdef OPENSSL_GPL_VIOLATION
- printf("Built with openssl (certificate) support. Be aware of the\n"
+ printf("Built with openssl certificate support. Be aware of the\n"
"license implications.\n");
#else /* OPENSSL_GPL_VIOLATION */
- printf("Built without openssl (certificate) support.\n");
+ printf("Built with certificate support.\n");
#endif /* OPENSSL_GPL_VIOLATION */
printf("\n");

@@ -699,13 +699,6 @@ void do_config(int argc, char **argv)
printf("%s: unknown authentication mode %s\nknown modes: psk cert hybrid\n", argv[0], config[CONFIG_AUTH_MODE]);
exit(1);
}
-#ifndef OPENSSL_GPL_VIOLATION
- if (opt_auth_mode == AUTH_MODE_HYBRID ||
- opt_auth_mode == AUTH_MODE_CERT) {
- printf("%s was built without openssl: Can't do hybrid or cert mode.\n", argv[0]);
- exit(1);
- }
-#endif
opt_no_encryption = (config[CONFIG_ENABLE_NO_ENCRYPTION]) ? 1 : 0;
opt_udpencapport=atoi(config[CONFIG_UDP_ENCAP_PORT]);

diff --git a/crypto-gnutls.c b/crypto-gnutls.c
new file mode 100644
index 0000000..d7ebd14
--- /dev/null
+++ b/crypto-gnutls.c
@@ -0,0 +1,540 @@
+/* IPSec VPN client compatible with Cisco equipment.
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <gcrypt.h>
+
+#include "config.h"
+#include "sysdep.h"
+#include "crypto.h"
+
+static int gnutls_initialized = 0;
+
+#define CERT_STACK_DEPTH 20
+
+crypto_ctx *crypto_ctx_new(crypto_error **error)
+{
+ crypto_ctx *ctx;
+
+ if (!gnutls_initialized) {
+ if (gnutls_global_init() != 0) {
+ crypto_error_set(error, 1, 0, "error initializing gnutls globals");
+ return NULL;
+ }
+ gnutls_initialized = 1;
+ }
+
+ ctx = gnutls_calloc(1, sizeof(crypto_ctx));
+ if (!ctx) {
+ crypto_error_set(error, 1, ENOMEM, "not enough memory for crypto context");
+ return NULL;
+ }
+
+ ctx->stack = gnutls_calloc(CERT_STACK_DEPTH, sizeof(gnutls_x509_crt_t));
+ if (!ctx->stack) {
+ crypto_ctx_free(ctx);
+ crypto_error_set(error, 1, ENOMEM,
+ "not enough memory for crypto certificate stack");
+ ctx = NULL;
+ }
+
+ return ctx;
+}
+
+void crypto_ctx_free(crypto_ctx *ctx)
+{
+ if (ctx) {
+ int i;
+
+ for (i = 0; i < ctx->num; i++)
+ gnutls_x509_crt_deinit(ctx->stack[i]);
+ gnutls_free(ctx->stack);
+ memset(ctx, 0, sizeof(crypto_ctx));
+ gnutls_free(ctx);
+ }
+}
+
+unsigned char *crypto_read_cert(const char *path,
+ size_t *out_len,
+ crypto_error **error)
+{
+ gnutls_x509_crt_t cert;
+ unsigned char *data = NULL;
+ gnutls_datum dt;
+ size_t fsize = 0;
+ int err;
+
+ dt.data = crypto_read_file(path, &fsize, error);
+ if (!dt.data)
+ return NULL;
+
+ dt.size = (unsigned int) fsize;
+ if (gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS) {
+ crypto_error_set(error, 1, ENOMEM, "not enough memory for certificate");
+ goto out;
+ }
+
+ err = gnutls_x509_crt_import(cert, &dt, GNUTLS_X509_FMT_PEM);
+ if (err != GNUTLS_E_SUCCESS)
+ err = gnutls_x509_crt_import(cert, &dt, GNUTLS_X509_FMT_DER);
+ if (err != GNUTLS_E_SUCCESS) {
+ crypto_error_set(error, 1, 0, "certificate (%s) format unknown", path);
+ goto out;
+ }
+
+ *out_len = 10000;
+ data = malloc(*out_len);
+ err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, data, out_len);
+ if (err != GNUTLS_E_SUCCESS) {
+ free(data);
+ *out_len = 0;
+ crypto_error_set(error, 1, 0, "certificate could not be exported");
+ }
+
+out:
+ if (dt.data)
+ gnutls_free(dt.data);
+ gnutls_x509_crt_deinit(cert);
+ return data;
+}
+
+int crypto_push_cert(crypto_ctx *ctx,
+ const unsigned char *data,
+ size_t len,
+ crypto_error **error)
+{
+ gnutls_x509_crt_t cert;
+ gnutls_datum dt;
+ int err;
+
+ if (!ctx || !data || (len <= 0)) {
+ crypto_error_set(error, 1, 0, "invalid crypto context or data");
+ return 1;
+ }
+
+ if (ctx->num >= CERT_STACK_DEPTH) {
+ crypto_error_set(error, 1, 0, "too many certificates in the chain.");
+ return 1;
+ }
+
+ gnutls_x509_crt_init (&cert);
+
+ dt.data = (unsigned char *) data;
+ dt.size = len;
+ err = gnutls_x509_crt_import (cert, &dt, GNUTLS_X509_FMT_DER);
+ if (err != GNUTLS_E_SUCCESS) {
+ gnutls_x509_crt_deinit (cert);
+ crypto_error_set(error, 1, 0, "failed to decode certificate");
+ return 1;
+ }
+
+ ctx->stack[ctx->num] = cert;
+ ctx->num++;
+ return 0;
+}
+
+static int verify_issuer(gnutls_x509_crt_t crt,
+ gnutls_x509_crt_t issuer,
+ crypto_error **error)
+{
+ unsigned int output;
+ time_t now = time (0);
+
+ if (gnutls_x509_crt_verify(crt, &issuer, 1, 0, &output) < 0) {
+ crypto_error_set(error, 1, 0, "failed to verify against issuer");
+ return 1;
+ }
+
+ if (output & GNUTLS_CERT_INVALID) {
+ if (output & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+ crypto_error_set(error, 1, 0, "certificate signer not found");
+ return 1;
+ }
+ if (output & GNUTLS_CERT_SIGNER_NOT_CA) {
+ crypto_error_set(error, 1, 0, "certificate signer not a CA");
+ return 1;
+ }
+ }
+
+ if (gnutls_x509_crt_get_activation_time(crt) > now) {
+ crypto_error_set(error, 1, 0, "certificate activation in the future");
+ return 1;
+ }
+
+ if (gnutls_x509_crt_get_expiration_time(crt) < now) {
+ crypto_error_set(error, 1, 0, "certificate expired");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int verify_last(gnutls_x509_crt_t crt,
+ gnutls_x509_crt_t *ca_list,
+ size_t ca_list_size,
+ crypto_error **error)
+{
+ unsigned int output;
+ time_t now = time (0);
+
+ if (gnutls_x509_crt_verify (crt, ca_list, ca_list_size,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+ &output) < 0) {
+ crypto_error_set(error, 1, 0, "failed to verify against CA list");
+ return 1;
+ }
+
+ if (output & GNUTLS_CERT_INVALID) {
+ if (output & GNUTLS_CERT_SIGNER_NOT_CA) {
+ crypto_error_set(error, 1, 0, "certificate signer not a CA");
+ return 1;
+ }
+ }
+
+ if (gnutls_x509_crt_get_activation_time(crt) > now) {
+ crypto_error_set(error, 1, 0, "certificate activation in the future");
+ return 1;
+ }
+
+ if (gnutls_x509_crt_get_expiration_time(crt) < now) {
+ crypto_error_set(error, 1, 0, "certificate expired");
+ return 1;
+ }
+
+ return 0;
+}
+
+static gnutls_x509_crt_t *load_one_ca_file(const char *path, crypto_error **error)
+{
+ gnutls_x509_crt_t *list = NULL;
+ gnutls_x509_crt_t cert;
+ gnutls_datum dt;
+ size_t fsize = 0;
+ int err;
+
+ dt.data = crypto_read_file(path, &fsize, error);
+ if (!dt.data)
+ return NULL;
+
+ dt.size = (unsigned int) fsize;
+ if (gnutls_x509_crt_init (&cert) != GNUTLS_E_SUCCESS) {
+ gnutls_free(dt.data);
+ crypto_error_set(error, 1, ENOMEM, "not enough memory for certificate");
+ goto out;
+ }
+
+ err = gnutls_x509_crt_import (cert, &dt, GNUTLS_X509_FMT_PEM);
+ if (err != GNUTLS_E_SUCCESS)
+ err = gnutls_x509_crt_import (cert, &dt, GNUTLS_X509_FMT_DER);
+ gnutls_free(dt.data);
+ if (err != GNUTLS_E_SUCCESS) {
+ crypto_error_set(error, 1, 0, "certificate (%s) format unknown", path);
+ goto out;
+ }
+
+ list = gnutls_malloc(sizeof(gnutls_x509_crt_t));
+ if (!list) {
+ crypto_error_set(error, 1, ENOMEM, "not enough memory for certificate list");
+ goto out;
+ } else
+ list[0] = cert;
+
+out:
+ gnutls_x509_crt_deinit (cert);
+ return list;
+}
+
+static gnutls_x509_crt_t *load_ca_list_file(const char *path,
+ size_t *out_list_size,
+ crypto_error **error)
+{
+ gnutls_x509_crt_t *list = NULL, *old;
+ gnutls_datum dt = { NULL, 0 };
+ size_t fsize = 0;
+ int err;
+ unsigned int num = 200;
+
+ dt.data = crypto_read_file(path, &fsize, error);
+ if (!dt.data)
+ return NULL;
+
+ dt.size = (unsigned int) fsize;
+ old = list = gnutls_malloc(sizeof(gnutls_x509_crt_t) * num);
+ if (!list) {
+ crypto_error_set(error, 1, ENOMEM, "not enough memory for CA list");
+ goto out;
+ }
+
+ err = gnutls_x509_crt_list_import(list, &num, &dt, GNUTLS_X509_FMT_PEM, 0);
+ if (err <= 0) {
+ /* DER then maybe */
+ gnutls_free(list);
+ list = load_one_ca_file(path, error);
+ if (!list)
+ goto out;
+ num = 1;
+ } else
+ num = err; /* gnutls_x509_crt_list_import() returns # read */
+
+ if (err < 0) {
+ crypto_error_set(error, 1, 0, "importing CA list (%d)", err);
+ gnutls_free(list);
+ list = NULL;
+ } else
+ *out_list_size = num;
+
+out:
+ gnutls_free(dt.data);
+ return list;
+}
+
+int crypto_verify_chain(crypto_ctx *ctx,
+ const char *ca_file,
+ const char *ca_dir,
+ crypto_error **error)
+{
+ int err, i, ret = 1, start = 0;
+ gnutls_x509_crt_t *ca_list = NULL;
+ size_t ca_list_size = 0;
+
+ if (!ctx)
+ return 1;
+
+ if (ctx->num == 0)
+ return 0;
+
+ if (ca_file) {
+ ca_list = load_ca_list_file(ca_file, &ca_list_size, error);
+ if (!ca_list)
+ return 1;
+ } else if (ca_dir) {
+ /* FIXME: Try to load all files in the directory I guess... */
+ crypto_error_set(error, 1, 0, "ca_dir not yet supported");
+ return 1;
+ }
+
+ /* If the server cert is self-signed, ignore it in the issuers check */
+ err = gnutls_x509_crt_check_issuer(ctx->stack[0], ctx->stack[0]);
+ if (err > 0)
+ start++;
+
+ /* Check each certificate against its issuer */
+ for (i = start; i < ctx->num - 1; i++) {
+ if (verify_issuer(ctx->stack[i], ctx->stack[i + 1], error))
+ goto out;
+ }
+
+ /* Verify the last certificate */
+ if (verify_last(ctx->stack[ctx->num - 1], ca_list, ca_list_size, error))
+ goto out;
+
+ ret = 0;
+
+out:
+ if (ca_list) {
+ for (i = 0; i < (int) ca_list_size; i++)
+ gnutls_x509_crt_deinit(ca_list[i]);
+ gnutls_free(ca_list);
+ }
+ return ret;
+}
+
+static unsigned char *check_pkcs1_padding(unsigned char* from,
+ size_t from_len,
+ size_t *out_len,
+ crypto_error **error)
+{
+ int i = 0;
+ unsigned char *rec_hash = NULL;
+ size_t hash_len = 0;
+
+ /* No function provided to check that hash conforms to
+ * PKCS#1 1.5 padding scheme. Moreover gcrypt trim first
+ * 0 bytes */
+ if (from[i++] != 0x01) {
+ crypto_error_set(error, 1, 0, "hash doesn't conform to PKCS#1 padding");
+ goto out;
+ }
+
+ while (from[i] != 0x00) {
+ if (from[i++] != 0xFF) {
+ crypto_error_set(error, 1, 0, "hash doesn't conform to PKCS#1 padding");
+ goto out;
+ }
+ }
+
+ i++; /* Skips 00 byte */
+
+ if (i < 10) {
+ crypto_error_set(error, 1, 0, "PKCS#1 padding too short");
+ goto out;
+ }
+
+ hash_len = from_len - i;
+ rec_hash = calloc(1, hash_len);
+ if (!rec_hash)
+ goto out;
+
+ memcpy(rec_hash, from + i, hash_len);
+ *out_len = hash_len;
+
+out:
+ return rec_hash;
+}
+
+
+unsigned char *crypto_decrypt_signature(crypto_ctx *ctx,
+ const unsigned char *sig_data,
+ size_t sig_len,
+ size_t *out_len,
+ unsigned int padding,
+ crypto_error **error)
+{
+ unsigned char *buf = NULL, *rec_hash = NULL;
+ gnutls_datum_t n = { NULL, 0 }, e = { NULL, 0 };
+ int err, algo;
+ gcry_sexp_t key = NULL, sig = NULL, decrypted = NULL, child = NULL;
+ gcry_mpi_t n_mpi = NULL, e_mpi = NULL, sig_mpi = NULL, dec_mpi = NULL;
+ size_t buf_len = 0, hash_len = 0;
+
+ if (!ctx) {
+ crypto_error_set(error, 1, 0, "invalid crypto context");
+ return NULL;
+ }
+
+ if (!ctx->num) {
+ crypto_error_set(error, 1, 0, "no certificates in the stack");
+ return NULL;
+ }
+
+ algo = gnutls_x509_crt_get_pk_algorithm(ctx->stack[ctx->num - 1], NULL);
+ if (algo != GNUTLS_PK_RSA) {
+ crypto_error_set(error, 1, 0, "certificate public key algorithm not RSA");
+ return NULL;
+ }
+
+ err = gnutls_x509_crt_get_pk_rsa_raw(ctx->stack[ctx->num - 1], &n, &e);
+ if (err != GNUTLS_E_SUCCESS) {
+ crypto_error_set(error, 1, 0, "error getting certificate public key");
+ return NULL;
+ }
+
+ err = gcry_mpi_scan(&n_mpi, GCRYMPI_FMT_USG, n.data, n.size, NULL);
+ if (err) {
+ crypto_error_set(error, 1, 0, "invalid RSA key 'n' format");
+ goto out;
+ }
+
+ err = gcry_mpi_scan(&e_mpi, GCRYMPI_FMT_USG, e.data, e.size, NULL);
+ if (err) {
+ crypto_error_set(error, 1, 0, "invalid RSA key 'e' format");
+ goto out;
+ }
+
+ err = gcry_sexp_build(&key, NULL, "(public-key (rsa (n %m) (e %m)))", n_mpi, e_mpi);
+ if (err) {
+ crypto_error_set(error, 1, 0, "could not create public-key expression");
+ goto out;
+ }
+
+ err = gcry_mpi_scan(&sig_mpi, GCRYMPI_FMT_USG, sig_data, sig_len, NULL);
+ if (err) {
+ crypto_error_set(error, 1, 0, "invalid signature format");
+ goto out;
+ }
+
+ err = gcry_sexp_build(&sig, NULL, "(data (flags raw) (value %m))", sig_mpi);
+ if (err) {
+ crypto_error_set(error, 1, 0, "could not create signature expression");
+ goto out;
+ }
+
+ /* encrypt is equivalent to public key decryption for RSA keys */
+ err = gcry_pk_encrypt(&decrypted, sig, key);
+ if (err) {
+ crypto_error_set(error, 1, 0, "could not decrypt signature");
+ goto out;
+ }
+
+ child = gcry_sexp_find_token(decrypted, "a", 1);
+ if (!child) {
+ crypto_error_set(error, 1, 0, "could not get decrypted signature result");
+ goto out;
+ }
+
+ dec_mpi = gcry_sexp_nth_mpi(child, 1, GCRYMPI_FMT_USG);
+ gcry_sexp_release(child);
+
+ if (!dec_mpi) {
+ crypto_error_set(error, 1, 0, "could not get decrypted signature result");
+ goto out;
+ }
+
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, &buf, &buf_len, dec_mpi);
+ if (!buf) {
+ crypto_error_set(error, 1, 0, "could not get extract decrypted signature");
+ goto out;
+ }
+
+ switch (padding) {
+ case CRYPTO_PAD_NONE:
+ rec_hash = buf;
+ hash_len = buf_len;
+ buf = NULL;
+ *out_len = (int) hash_len;
+ break;
+ case CRYPTO_PAD_PKCS1:
+ rec_hash = check_pkcs1_padding(buf, buf_len, &hash_len, error);
+ if (!rec_hash) {
+ crypto_error_set(error, 1, 0, "could not get extract decrypted padded signature");
+ goto out;
+ }
+ *out_len = (int) hash_len;
+ break;
+ default:
+ crypto_error_set(error, 1, 0, "unknown padding mechanism %d", padding);
+ break;
+ }
+
+out:
+ if (buf)
+ free(buf);
+ if (dec_mpi)
+ gcry_mpi_release(dec_mpi);
+ if (decrypted)
+ gcry_sexp_release(decrypted);
+ if (key)
+ gcry_sexp_release(key);
+ if (sig)
+ gcry_sexp_release(sig);
+ if (sig_mpi)
+ gcry_mpi_release(sig_mpi);
+ if (n_mpi)
+ gcry_mpi_release(n_mpi);
+ if (e_mpi)
+ gcry_mpi_release(e_mpi);
+ if (n.data)
+ gcry_free(n.data);
+ if (e.data)
+ gcry_free(e.data);
+
+ return rec_hash;
+}
+
diff --git a/crypto-gnutls.h b/crypto-gnutls.h
new file mode 100644
index 0000000..31443fc
--- /dev/null
+++ b/crypto-gnutls.h
@@ -0,0 +1,30 @@
+/* IPSec VPN client compatible with Cisco equipment.
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __CRYPTO_GNUTLS_H__
+#define __CRTPTO_GNUTLS_H__
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+typedef struct {
+ int num;
+ gnutls_x509_crt_t *stack;
+} crypto_ctx;
+
+#endif /* __CRYPTO_GNUTLS_H__ */
+
diff --git a/crypto-openssl.c b/crypto-openssl.c
new file mode 100644
index 0000000..d3c057c
--- /dev/null
+++ b/crypto-openssl.c
@@ -0,0 +1,323 @@
+/* IPSec VPN client compatible with Cisco equipment.
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <openssl/pem.h>
+#include "config.h"
+#include "sysdep.h"
+#include "crypto.h"
+
+crypto_ctx *crypto_ctx_new(crypto_error **error)
+{
+ crypto_ctx *ctx;
+
+ ctx = malloc(sizeof(crypto_ctx));
+ if (!ctx) {
+ crypto_error_set(error, 1, ENOMEM,
+ "not enough memory for crypto context");
+ return NULL;
+ }
+
+ OpenSSL_add_all_ciphers();
+ OpenSSL_add_all_digests();
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ memset(ctx, 0, sizeof(crypto_ctx));
+ ctx->stack = sk_X509_new_null();
+ if (!ctx->stack) {
+ crypto_ctx_free(ctx);
+ crypto_error_set(error, 1, ENOMEM,
+ "not enough memory for crypto certificate stack");
+ ctx = NULL;
+ }
+
+ return ctx;
+}
+
+void crypto_ctx_free(crypto_ctx *ctx)
+{
+ if (ctx) {
+ if (ctx->stack)
+ sk_X509_free(ctx->stack);
+
+ memset(ctx, 0, sizeof(crypto_ctx));
+ free(ctx);
+ }
+}
+
+static int password_cb(char *buf, int size, int rwflag, void *userdata)
+{
+ /* Dummy callback to ensure openssl doesn't prompt for a password */
+ return 0;
+}
+
+unsigned char *crypto_read_cert(const char *path,
+ size_t *out_len,
+ crypto_error **error)
+{
+ FILE *fp;
+ X509 *cert = NULL;
+ unsigned char *data = NULL, *p;
+
+ fp = fopen(path, "r");
+ if (!fp) {
+ crypto_error_set(error, 1, 0, "certificate (%s) could not be opened", path);
+ return NULL;
+ }
+
+ cert = PEM_read_X509(fp, NULL, password_cb, NULL);
+ fclose (fp);
+
+ if (!cert) {
+ /* Try DER then */
+ p = data = crypto_read_file(path, out_len, error);
+ if (!data || !*out_len) {
+ crypto_error_set(error, 1, 0, "could not read certificate %s", path);
+ return NULL;
+ }
+
+ cert = d2i_X509(NULL, (const unsigned char **) &p, (int) (*out_len));
+ if (!cert) {
+ free(data);
+ crypto_error_set(error, 1, 0, "could not allocate memory for certificate");
+ return NULL;
+ }
+
+ return data;
+ }
+
+ /* Get length of DER data */
+ *out_len = i2d_X509(cert, NULL);
+ if (!*out_len) {
+ crypto_error_set(error, 1, 0, "invalid certificate length");
+ goto out;
+ }
+
+ p = data = malloc(*out_len);
+ if (!data) {
+ crypto_error_set(error, 1, 0, "could not allocate memory for certificate");
+ goto out;
+ }
+
+ /* Encode the certificate to DER */
+ *out_len = i2d_X509(cert, &p);
+ if (!*out_len) {
+ crypto_error_set(error, 1, 0, "could not export certificate data");
+ if (data) {
+ free(data);
+ data = NULL;
+ }
+ goto out;
+ }
+
+out:
+ if (cert)
+ X509_free(cert);
+ return data;
+}
+
+int crypto_push_cert(crypto_ctx *ctx,
+ const unsigned char *data,
+ size_t len,
+ crypto_error **error)
+{
+ X509 *cert = NULL;
+
+ if (!ctx || !data || (len <= 0)) {
+ crypto_error_set(error, 1, 0, "invalid crypto context or data");
+ return 1;
+ }
+
+ /* convert the certificate to an openssl-X509 structure and push it onto the chain stack */
+ cert = d2i_X509(NULL, &data, (int) len);
+ if (!cert) {
+ ERR_print_errors_fp(stderr);
+ crypto_error_set(error, 1, 0, "failed to decode certificate");
+ return 1;
+ }
+ sk_X509_push(ctx->stack, cert);
+ return 0;
+}
+
+int crypto_verify_chain(crypto_ctx *ctx,
+ const char *ca_file,
+ const char *ca_dir,
+ crypto_error **error)
+{
+ X509 *x509;
+ X509_STORE *store = NULL;
+ X509_LOOKUP *lookup = NULL;
+ X509_STORE_CTX *verify_ctx = NULL;
+ int ret = 1;
+
+ if (!ctx) {
+ crypto_error_set(error, 1, 0, "invalid crypto context");
+ return 1;
+ }
+
+ x509 = sk_X509_value(ctx->stack, sk_X509_num(ctx->stack) - 1);
+ if (x509 == NULL) {
+ ERR_print_errors_fp (stderr);
+ crypto_error_set(error, 1, 0, "no certificates in the stack");
+ return 1;
+ }
+
+ /* BEGIN - verify certificate chain */
+ /* create the cert store */
+ if (!(store = X509_STORE_new())) {
+ crypto_error_set(error, 1, 0, "error creating X509_STORE object");
+ return 1;
+ }
+ /* load the CA certificates */
+ if (X509_STORE_load_locations (store, ca_file, ca_dir) != 1) {
+ crypto_error_set(error, 1, 0, "error loading the CA file (%s) "
+ "or directory (%s)", ca_file, ca_dir);
+ goto out;
+ }
+ if (X509_STORE_set_default_paths (store) != 1) {
+ crypto_error_set(error, 1, 0, "error loading the system-wide CA"
+ " certificates");
+ goto out;
+ }
+
+#if 0
+ /* check CRLs */
+ /* add the corresponding CRL for each CA in the chain to the lookup */
+#define CRL_FILE "root-ca-crl.crl.pem"
+
+ if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))) {
+ crypto_error_set(error, 1, 0, "error creating X509 lookup object.");
+ goto out;
+ }
+ if (X509_load_crl_file(lookup, CRL_FILE, X509_FILETYPE_PEM) != 1) {
+ ERR_print_errors_fp(stderr);
+ crypto_error_set(error, 1, 0, "error reading CRL file");
+ goto out;
+ }
+ X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+#endif /* 0 */
+
+ /* create a verification context and initialize it */
+ if (!(verify_ctx = X509_STORE_CTX_new ())) {
+ crypto_error_set(error, 1, 0, "error creating X509_STORE_CTX object");
+ goto out;
+ }
+ /* X509_STORE_CTX_init did not return an error condition in prior versions */
+ if (X509_STORE_CTX_init (verify_ctx, store, x509, ctx->stack) != 1) {
+ crypto_error_set(error, 1, 0, "error intializing verification context");
+ goto out;
+ }
+
+ /* verify the certificate */
+ if (X509_verify_cert(verify_ctx) != 1) {
+ ERR_print_errors_fp(stderr);
+ crypto_error_set(error, 2, 0, "error verifying the certificate "
+ "chain");
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ if (lookup)
+ X509_LOOKUP_free(lookup);
+ if (store)
+ X509_STORE_free(store);
+ if (verify_ctx)
+ X509_STORE_CTX_free(verify_ctx);
+ return ret;
+}
+
+unsigned char *crypto_decrypt_signature(crypto_ctx *ctx,
+ const unsigned char *sig_data,
+ size_t sig_len,
+ size_t *out_len,
+ unsigned int padding,
+ crypto_error **error)
+{
+ X509 *x509;
+ EVP_PKEY *pkey = NULL;
+ RSA *rsa;
+ unsigned char *hash = NULL;
+ int tmp_len = -1, ossl_pad;
+
+ *out_len = 0;
+
+ if (!ctx) {
+ crypto_error_set(error, 1, 0, "invalid crypto context");
+ return NULL;
+ }
+
+ x509 = sk_X509_value(ctx->stack, sk_X509_num(ctx->stack) - 1);
+ if (x509 == NULL) {
+ ERR_print_errors_fp (stderr);
+ crypto_error_set(error, 1, 0, "no certificates in the stack");
+ return NULL;
+ }
+
+ pkey = X509_get_pubkey(x509);
+ if (pkey == NULL) {
+ ERR_print_errors_fp (stderr);
+ crypto_error_set(error, 1, 0, "error getting certificate public key");
+ return NULL;
+ }
+
+ rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa == NULL) {
+ ERR_print_errors_fp (stderr);
+ crypto_error_set(error, 1, 0, "error getting public key RSA");
+ goto out;
+ }
+
+ hash = calloc(1, RSA_size(rsa));
+ if (!hash) {
+ crypto_error_set(error, 1, 0, "not enough memory to decrypt signature");
+ goto out;
+ }
+
+ switch (padding) {
+ case CRYPTO_PAD_NONE:
+ ossl_pad = RSA_NO_PADDING;
+ break;
+ case CRYPTO_PAD_PKCS1:
+ ossl_pad = RSA_PKCS1_PADDING;
+ break;
+ default:
+ crypto_error_set(error, 1, 0, "unknown padding mechanism %d", padding);
+ goto out;
+ }
+
+ tmp_len = RSA_public_decrypt(sig_len, sig_data, hash, rsa, ossl_pad);
+ if (tmp_len > 0) {
+ *out_len = (size_t) tmp_len;
+ } else {
+ ERR_print_errors_fp (stderr);
+ crypto_error_set(error, 1, 0, "could not decrypt signature");
+ free(hash);
+ hash = NULL;
+ }
+
+out:
+ if (pkey)
+ EVP_PKEY_free(pkey);
+ return hash;
+}
+
diff --git a/crypto-openssl.h b/crypto-openssl.h
new file mode 100644
index 0000000..57ac883
--- /dev/null
+++ b/crypto-openssl.h
@@ -0,0 +1,33 @@
+/* IPSec VPN client compatible with Cisco equipment.
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef OPENSSL_GPL_VIOLATION
+#error "openssl support cannot be built without defining OPENSSL_GPL_VIOLATION"
+#endif
+
+#ifndef __CRYPTO_OPENSSL_H__
+#define __CRYPTO_OPENSSL_H__
+
+#include <openssl/x509.h>
+#include <openssl/err.h>
+
+typedef struct {
+ STACK_OF(X509) *stack;
+} crypto_ctx;
+
+#endif /* __CRYPTO_OPENSSL_H__ */
+
diff --git a/crypto.c b/crypto.c
new file mode 100644
index 0000000..62fb371
--- /dev/null
+++ b/crypto.c
@@ -0,0 +1,143 @@
+/* IPSec VPN client compatible with Cisco equipment.
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "crypto.h"
+
+
+#define MSG_SIZE 200
+void crypto_error_set(crypto_error **error,
+ int code,
+ int in_errno,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ if (!error)
+ return;
+ if (*error) {
+ fprintf(stderr, "%s: called with non-NULL *error\n", __func__);
+ return;
+ }
+
+ *error = calloc(1, sizeof(crypto_error));
+ if (!*error)
+ return;
+
+ (*error)->code = code;
+ (*error)->err = in_errno;
+
+ (*error)->msg = malloc(MSG_SIZE);
+ if (!(*error)->msg) {
+ fprintf(stderr, "%s: not enough memory for error message\n", __func__);
+ crypto_error_clear(error);
+ return;
+ }
+
+ va_start(args, fmt);
+ if (vsnprintf((*error)->msg, MSG_SIZE, fmt, args) == -1)
+ (*error)->msg[0] = '\0';
+ va_end(args);
+}
+
+void crypto_error_free(crypto_error *error)
+{
+ if (error) {
+ if (error->msg)
+ free(error->msg);
+ memset(error, 0, sizeof(crypto_error));
+ free(error);
+ }
+}
+
+void crypto_error_clear(crypto_error **error)
+{
+ if (error && *error) {
+ crypto_error_free(*error);
+ *error = NULL;
+ }
+}
+
+void crypto_call_error(crypto_error *err)
+{
+ if (err)
+ error(err->code, err->err, "%s\n", err->msg);
+ else
+ error(1, 0, "unknown error");
+}
+
+unsigned char *
+crypto_read_file(const char *path, size_t *out_len, crypto_error **error)
+{
+ struct stat st;
+ int fd;
+ ssize_t bytes_read;
+ size_t file_size;
+ unsigned char *data = NULL;
+
+ *out_len = 0;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ crypto_error_set(error, 1, errno, "failed to open file '%s'", path);
+ return NULL;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ crypto_error_set(error, 1, errno, "failed to stat file '%s'", path);
+ goto out;
+ }
+
+ if (st.st_size <= 0 || st.st_size > INT_MAX) {
+ crypto_error_set(error, 1, errno, "invalid file '%s' length %ld", path, st.st_size);
+ goto out;
+ }
+
+ file_size = st.st_size;
+ data = malloc(file_size);
+ if (!data) {
+ crypto_error_set(error, 1, ENOMEM, "not enough memory to read file '%s'", path);
+ goto out;
+ }
+
+ do {
+ bytes_read = read(fd, &(data[*out_len]), (st.st_size - *out_len));
+ if (bytes_read < 0) {
+ free(data);
+ data = NULL;
+ *out_len = 0;
+ crypto_error_set(error, 1, errno, "failed to read file '%s'", path);
+ goto out;
+ }
+ *out_len += bytes_read;
+ } while ((bytes_read > 0) && (*out_len <= file_size));
+
+out:
+ close(fd);
+ return data;
+}
+
diff --git a/crypto.h b/crypto.h
new file mode 100644
index 0000000..88fa5bb
--- /dev/null
+++ b/crypto.h
@@ -0,0 +1,139 @@
+/* IPSec VPN client compatible with Cisco equipment.
+
+ 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.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef __CRYPTO_H__
+#define __CRYPTO_H__
+
+#include <stdarg.h>
+
+typedef struct {
+ int code;
+ int err;
+ char *msg;
+} crypto_error;
+
+void crypto_error_set(crypto_error **error, int code, int in_errno, const char *fmt, ...);
+
+void crypto_error_free(crypto_error *error);
+
+void crypto_error_clear(crypto_error **error);
+
+void crypto_call_error(crypto_error *err);
+
+unsigned char *crypto_read_file(const char *path, size_t *out_len, crypto_error **error);
+
+#if CRYPTO_GNUTLS
+#include "crypto-gnutls.h"
+#elif CRYPTO_OPENSSL
+#include "crypto-openssl.h"
+#else
+#error "no crypto library defined"
+#endif
+
+#define CRYPTO_PAD_NONE 0
+#define CRYPTO_PAD_PKCS1 1
+
+/**
+ * crypto_push_cert:
+ *
+ * Allocates a crypto context with the resources necessary for the specific
+ * crypto library being used.
+ *
+ * Returns: a valid crypto context, or #NULL on error
+ **/
+crypto_ctx *crypto_ctx_new(crypto_error **error);
+
+/**
+ * crypto_ctx_free:
+ * @ctx: a valid crypto context created with crypto_ctx_new()
+ *
+ * Frees resources allocated by crypo_ctx_new().
+ **/
+void crypto_ctx_free(crypto_ctx *ctx);
+
+/**
+ * crypto_read_cert:
+ * @path: path to certificate file in either PEM or DER format
+ * @out_len: length of raw certificate data
+ * @error: return location for an error
+ *
+ * Loads a certificate and returns the binary ASN certificate data;
+ *
+ * Returns: certificate data on success, NULL on error
+ **/
+unsigned char *crypto_read_cert(const char *path,
+ size_t *out_len,
+ crypto_error **error);
+
+/**
+ * crypto_push_cert:
+ * @ctx: a valid crypto context created with crypto_ctx_new()
+ * @data: buffer containing raw certificate data
+ * @len: length of raw certificate data
+ * @error: return location for an error
+ *
+ * Pushes the given certificate onto the context's certificate stack.
+ *
+ * Returns: 0 on success, 1 on error
+ **/
+int crypto_push_cert(crypto_ctx *ctx,
+ const unsigned char *data,
+ size_t len,
+ crypto_error **error);
+
+/**
+ * crypto_verify_chain:
+ * @ctx: a valid crypto context created with crypto_ctx_new()
+ * @ca_file: path of a CA certificate file to use for verification of the
+ * certificate stack. File may be a PEM-encoded file containing
+ * multiple CA certificates. @ca_file is preferred over @ca_dir
+ * @ca_dir: directory containing CA certificates to use for verification of the
+ * certificate stack
+ * @error: return location for an error
+ *
+ * Verifies the certificate stack previously built with crypto_push_cert() using
+ * the supplied CA certificates or certificate locations.
+ *
+ * Returns: 0 on success, 1 on error
+ **/
+int crypto_verify_chain(crypto_ctx *ctx,
+ const char *ca_file,
+ const char *ca_dir,
+ crypto_error **error);
+
+/**
+ * crypto_decrypt_signature:
+ * @ctx: a valid crypto context created with crypto_ctx_new()
+ * @sig_data: encrypted signature data
+ * @sig_len: length of encrypted signature data
+ * @out_len: size of decrypted signature data
+ * @error: return location for an error
+ *
+ * Recovers the message digest stored in @sig_data using the public key of the
+ * last certificate on the certificate stack
+ *
+ * Returns: decrypted message digest, or #NULL on error
+ **/
+unsigned char *crypto_decrypt_signature(crypto_ctx *ctx,
+ const unsigned char *sig_data,
+ size_t sig_len,
+ size_t *out_hash_len,
+ unsigned int padding,
+ crypto_error **error);
+
+#endif /* __CRYPTO_H__ */
+
diff --git a/supp.c b/supp.c
index 3ff88f0..d029ea0 100644
--- a/supp.c
+++ b/supp.c
@@ -55,14 +55,12 @@ const supported_algo_t supp_crypt[] = {
const supported_algo_t supp_auth[] = {
{"psk", 0, IKE_AUTH_PRESHARED, 0, 0},
{"psk+xauth", 0, IKE_AUTH_XAUTHInitPreShared, 0, 0},
-#ifdef OPENSSL_GPL_VIOLATION
#if 0
{"cert(dsa)", 0, IKE_AUTH_RSA_SIG, 0, 0},
{"cert(rsasig)", 0, IKE_AUTH_DSS, 0, 0},
{"hybrid(dsa)", 0, IKE_AUTH_DSS, 0, 0},
#endif /* 0 */
{"hybrid(rsa)", 0, IKE_AUTH_HybridInitRSA, 0, 0},
-#endif /* OPENSSL_GPL_VIOLATION */
{NULL, 0, 0, 0, 0}
};

diff --git a/test/cert0.pem b/test/cert0.pem
new file mode 100644
index 0000000..51b0bf5
--- /dev/null
+++ b/test/cert0.pem
@@ -0,0 +1,36 @@
+ 0 s:/1.3.6.1.4.1.311.60.2.1.3=CH/1.3.6.1.4.1.311.60.2.1.2=Bern/2.5.4.15=V1.0, Clause 5(b)/serialNumber=CH-035.7.001.278-9/C=CH/ST=Zuerich/L=Zuerich/O=SWITCH/CN=www.switch.ch
+ i:/C=BM/O=QuoVadis Limited/OU=www.quovadisglobal.com/CN=QuoVadis Global SSL ICA
+-----BEGIN CERTIFICATE-----
+MIIFpjCCBI6gAwIBAgICD4YwDQYJKoZIhvcNAQEFBQAwazELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHzAdBgNVBAsTFnd3dy5xdW92YWRp
+c2dsb2JhbC5jb20xIDAeBgNVBAMTF1F1b1ZhZGlzIEdsb2JhbCBTU0wgSUNBMB4X
+DTA5MDExNTA5MjEzM1oXDTExMDExNTA5MjEzM1owgb8xEzARBgsrBgEEAYI3PAIB
+AxMCQ0gxFTATBgsrBgEEAYI3PAIBAhMEQmVybjEaMBgGA1UEDxMRVjEuMCwgQ2xh
+dXNlIDUoYikxGzAZBgNVBAUTEkNILTAzNS43LjAwMS4yNzgtOTELMAkGA1UEBhMC
+Q0gxEDAOBgNVBAgTB1p1ZXJpY2gxEDAOBgNVBAcTB1p1ZXJpY2gxDzANBgNVBAoT
+BlNXSVRDSDEWMBQGA1UEAxMNd3d3LnN3aXRjaC5jaDCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAKqwpnO5zcYxC829nQpHkFeZp9Hp4gzlyvHj0BHaLx9F
+pQxaFw7bsgbrMR+M+OjI+NXbWhPbc6ftY5VjqYwaVQAWmA3vvo5ELsy11lzyQusi
+ZT2wjx0Rx1SV7ocP20rDS0gkFqrej0ymdQKO/mcyht53a076goaUuacOElhNttlM
+baXiGwSMFURVUA/9dcOC8HhYPokzWnQD7BkFl3pg3BsmHz5mQ+rh79e+rKJylsXS
+qfSI1zD0QQTLd01JBzX4iOM37IlHBAJb/EWAuNJPjA9SHZlfILhphaAiEtKUlcyL
+4atAUUgbM2SI9yFfwALHliyBgoBcsZSd7ZlzhaFVA6UCAwEAAaOCAf0wggH5MHQG
+CCsGAQUFBwEBBGgwZjAqBggrBgEFBQcwAYYeaHR0cDovL29jc3AucXVvdmFkaXNn
+bG9iYWwuY29tMDgGCCsGAQUFBzAChixodHRwOi8vdHJ1c3QucXVvdmFkaXNnbG9i
+YWwuY29tL3F2c3NsaWNhLmNydDBRBgNVHSAESjBIMEYGDCsGAQQBvlgAAmQBAjA2
+MDQGCCsGAQUFBwIBFihodHRwOi8vd3d3LnF1b3ZhZGlzZ2xvYmFsLmNvbS9yZXBv
+c2l0b3J5MIGEBgNVHREEfTB7gg13d3cuc3dpdGNoLmNogglzd2l0Y2guY2iCEXd3
+dy1kYXYuc3dpdGNoLmNoggxjbXMuc21zY2cuY2iCEWNtcy53d3cuc3dpdGNoLmNo
+ggllZHVodWIuY2iCDXd3dy5lZHVodWIuY2iCEWNtcy53d3cuZWR1aHViLmNoMAsG
+A1UdDwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwHwYDVR0j
+BBgwFoAUMk2hT+rwrpm27psHLIQIEVCL4n4wOwYDVR0fBDQwMjAwoC6gLIYqaHR0
+cDovL2NybC5xdW92YWRpc2dsb2JhbC5jb20vcXZzc2xpY2EuY3JsMB0GA1UdDgQW
+BBRj4EuKFVw3hT+IAecPzu1V+KBfRDANBgkqhkiG9w0BAQUFAAOCAQEAOGUv6vmY
+Bz1d8aewypeEpfGG6HEM59xXEnawhywiT7642y0ZCrAIYQASpKhI4sLPKOJpmQRg
+IzApWKaYvLhUsqvnaEvGS+zj+WGvPps7Ky23mwNmLr4qlMdlW6HuXacZvePAUp9v
+qCzQzcxD2QRncZ1vmG1uz/2gR34b/pgb2HnUS4tT6HbUQxTbQAEEbRubTMjFAD5w
+MXIFvNdOl+fhsehC9xxRnXy0dprXE2Wtk29fqnnXmpTSaOOuzc5BhXamdjebCeY/
+ACI+6A2o7ZbwRLN/J/lnBItJuWam78u0ypLOpWpDImt7eWMP+3JjJcegxVwp80dU
+2TumER72gt2EOA==
+-----END CERTIFICATE-----
+
diff --git a/test/cert1.pem b/test/cert1.pem
new file mode 100644
index 0000000..d734bd7
--- /dev/null
+++ b/test/cert1.pem
@@ -0,0 +1,34 @@
+ 1 s:/C=BM/O=QuoVadis Limited/OU=www.quovadisglobal.com/CN=QuoVadis Global SSL ICA
+ i:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 2
+-----BEGIN CERTIFICATE-----
+MIIFTjCCAzagAwIBAgICBXowDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNzAxMTIxNjEzMzNaFw0xNzAxMTIxNjEzMTFaMGsxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR8wHQYDVQQLExZ3d3cu
+cXVvdmFkaXNnbG9iYWwuY29tMSAwHgYDVQQDExdRdW9WYWRpcyBHbG9iYWwgU1NM
+IElDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKk1mD/CiG1+aGcM
+xI7LJL0x4qQpmljkCt1BFL1oaoyuFW4l0GKVTNPFsJ6w4a7pLejG1uQJgeRmKy8n
+xm12NXgIshfqBvTqVFAcuGViwCreo5S+oZWlLxTIYRVJZB3OujED5IyXVibMLR7g
+xWwcXS2BCSNDUnCAN2x+sGHSR9o4sGTbiYFMZPWZfOc0rIbWtms/cUSVfqneyRGN
+WgoIvKPdT2vGvf70RpszxqjEEBLT2A1F2QwM/BxgxylzyelGCN6qVDJrE2rP1KRq
+AN+qiV7kK9MphZ9RYRkjtHE3qNkIxTi4KLy/FBWCy9abwK7t8+AGP6y+N8Oxf7Ed
+9AU37VcCAwEAAaOCASAwggEcMA8GA1UdEwEB/wQFMAMBAf8wOgYIKwYBBQUHAQEE
+LjAsMCoGCCsGAQUFBzABhh5odHRwOi8vb2NzcC5xdW92YWRpc2dsb2JhbC5jb20w
+QgYDVR0gBDswOTA3BgRVHSAAMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVv
+dmFkaXNnbG9iYWwuY29tL2NwczAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAU
+GoRivEhMMyUE1O7Q9gPEGUbRlGswOQYDVR0fBDIwMDAuoCygKoYoaHR0cDovL2Ny
+bC5xdW92YWRpc2dsb2JhbC5jb20vcXZyY2EyLmNybDAdBgNVHQ4EFgQUMk2hT+rw
+rpm27psHLIQIEVCL4n4wDQYJKoZIhvcNAQEFBQADggIBAI5zWxH+LIAvrc/dYIWZ
+8zHozDuc1kbd7IaiSgjJCZwNo1vMSLbNfgPg7XIoTDJ903URzDUWh4l8/XncwRil
+rRafR23N/iFkM+NF+LoABd9qpF/oAmOGuJ6GwPUf/yhioc8nQ/WXuMVF4/OTdvGF
+0QRsk7rivttpGx2aQhGBwO39ft4cySvXToNsBjH4VWcduEooZDg6plIec8S2zrFA
+dXvxSgz/sV41QHwyUokTxEY1UoXF9aA5VeGLKIkC1NasTyy26bzuOYOKxgqRUXIu
+n6M+CdWiKKJWVi3rBpbnFQWSrsotp4jeQn9zBuovTR0OOijTBWHj9ThxrIG5pb4g
+Nmd03/NZDe5l3ja59+UtBUpfCbdqPCCZSUy7t6PLAoDo5JwQKCEOrmNpwD/207GP
+2WMo77wh5/mvJRJMFfEZ+CwQXk5LPXXU7EJr+7PYpJB67hryxts1I6FJI0AF3ET9
+3YZ4sgEK009h6bdeZbIOvcT4e0v33EAJggFtxU/5xRdtk/PmwxBjSxeg+jBK2xeH
+3TScxc6nNvtcw22Lds5GucMsoxmpblYV1adrowg3twQvSXQZ96jzyT3qfmk09M+e
+bBTqd3GFwZcJNaQigOw8EQHQtjJm9Zco7FtJ+SxEqcQYFJ+M7QZz+0wWCPwlflMo
+7aGlYILpWH4iR3ZhuH/3xMkx
+-----END CERTIFICATE-----
+
diff --git a/test/cert2.pem b/test/cert2.pem
new file mode 100644
index 0000000..c1f00ad
--- /dev/null
+++ b/test/cert2.pem
@@ -0,0 +1,34 @@
+ 2 s:/C=BM/O=QuoVadis Limited/CN=QuoVadis Root CA 2
+ i:/C=BM/O=QuoVadis Limited/OU=Root Certification Authority/CN=QuoVadis Root Certification Authority
+-----BEGIN CERTIFICATE-----
+MIIFQjCCBCqgAwIBAgIEQh/RwTANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNzA3MTAxNDMyMjFaFw0xNzA3MTAxNDMx
+MDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRsw
+GQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+j
+hiYaHv5+HBg6XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp
+3MJGF/hd/aTa/55JWpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02
+kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw
+419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7ds
+E/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3
+FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslW
+ZvB1JdxnwQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C31
+5eXbyOD/5YDXC2Og/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9
+gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqL
+ID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQAB
+o4H/MIH8MA8GA1UdEwEB/wQFMAMBAf8wQgYDVR0gBDswOTA3BgRVHSAAMC8wLQYI
+KwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczA6Bggr
+BgEFBQcBAQQuMCwwKgYIKwYBBQUHMAGGHmh0dHA6Ly9vY3NwLnF1b3ZhZGlzZ2xv
+YmFsLmNvbTAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUi0tt7dMpuQYZ7Dk5
+qfCXhGrL798wOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2NybC5xdW92YWRpc2ds
+b2JhbC5jb20vcXZyY2EuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBMcgnQQhxa0o7B
+SMNVmyE8suH3nmg3+FC6sAWUsYEKZUZU+PdUrOYGTybAjdPSghSzyhWf/h+l1zwb
+/vxiaZET3ikOni1G1L9rmNPNd0o8Omr/sxTtNyCIEugoJtiBV324XD9wjYr4TjzH
+fn5pq33j+5iqCS0oaynouNevRB/Kcn36esUBg5eEL84cu7JxoOgyPxIccskf5Zp+
+4pqUlQod9cedCi2NaSJ6ZyNExTTtsWXRZM2DYfwMNilHBwPhgj472vQqxN3wb7f6
+ndMU7j2DXbO6G9V891AT1OM6J0JC1DYaA4bMr4m31lJs2sIn99IgrondrOsPSWuu
+TYzbyDZK
+-----END CERTIFICATE-----
+
diff --git a/test/root.pem b/test/root.pem
new file mode 100644
index 0000000..0050532
--- /dev/null
+++ b/test/root.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
+MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
+IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
+dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
+li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
+rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
+WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
+F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
+xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
+Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
+dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
+ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
+IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
+c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
+ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
+KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
+KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
+y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
+dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
+VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
+fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
+7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
+cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
+mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
+xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
+SnQ2+Q==
+-----END CERTIFICATE-----
+
diff --git a/vpnc.c b/vpnc.c
index 3a9de27..b36c7d5 100644
--- a/vpnc.c
+++ b/vpnc.c
@@ -40,12 +40,7 @@

#include <gcrypt.h>

-#ifdef OPENSSL_GPL_VIOLATION
-/* OpenSSL */
-#include <openssl/x509.h>
-#include <openssl/err.h>
-#endif /* OPENSSL_GPL_VIOLATION */
-
+#include "crypto.h"
#include "sysdep.h"
#include "config.h"
#include "isakmp-pkt.h"
@@ -1303,13 +1298,12 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
DEBUGTOP(2, printf("S4.4 AM_packet2\n"));
/* Decode the recieved packet. */
{
- int reject;
+ int reject, ret;
struct isakmp_packet *r;
struct isakmp_payload *rp;
struct isakmp_payload *nonce = NULL;
struct isakmp_payload *ke = NULL;
struct isakmp_payload *hash = NULL;
- struct isakmp_payload *last_cert = NULL;
struct isakmp_payload *sig = NULL;
struct isakmp_payload *idp = NULL;
int seen_sa = 0, seen_xauth_vid = 0;
@@ -1319,12 +1313,12 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
uint8_t *dh_shared_secret;
int seen_natt_vid = 0, seen_natd = 0, seen_natd_them = 0, seen_natd_us = 0;
int natt_draft = -1;
+ crypto_ctx *cctx;
+ crypto_error *crerr = NULL;

-#ifdef OPENSSL_GPL_VIOLATION
- X509 *current_cert;
- /* structure to store the certificate chain */
- STACK_OF(X509) *cert_stack = sk_X509_new_null();
-#endif /* OPENSSL_GPL_VIOLATION */
+ cctx = crypto_ctx_new (&crerr);
+ if (crerr)
+ crypto_call_error(crerr);

reject = 0;
r = parse_isakmp_packet(r_packet, r_length, &reject);
@@ -1482,14 +1476,15 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
hash = rp;
break;
case ISAKMP_PAYLOAD_CERT:
- last_cert = rp;
- if (last_cert->u.cert.encoding == ISAKMP_CERT_X509_SIG) {
-#ifdef OPENSSL_GPL_VIOLATION
- /* convert the certificate to an openssl-X509 structure and push it onto the chain stack */
- current_cert = d2i_X509(NULL, (const unsigned char **)&last_cert->u.cert.data, last_cert->u.cert.length);
- sk_X509_push(cert_stack, current_cert);
- last_cert->u.cert.data -= last_cert->u.cert.length; /* 'rewind' the pointer */
-#endif /* OPENSSL_GPL_VIOLATION */
+ if (rp->u.cert.encoding == ISAKMP_CERT_X509_SIG) {
+ hex_dump("cert", rp->u.cert.data, rp->u.cert.length, NULL);
+
+ ret = crypto_push_cert(cctx,
+ (const unsigned char *) rp->u.cert.data,
+ rp->u.cert.length,
+ &crerr);
+ if (ret)
+ crypto_call_error(crerr);
}
break;
case ISAKMP_PAYLOAD_SIG:
@@ -1677,9 +1672,10 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
/* Verify the hash. */
{
gcry_md_hd_t hm;
- unsigned char *expected_hash;
+ unsigned char *expected_hash, *rec_hash;
uint8_t *idp_f;
size_t idp_size;
+ size_t decr_size = 0;

flatten_isakmp_payload(idp, &idp_f, &idp_size);

@@ -1703,104 +1699,34 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
hex_dump("received hash", hash->u.hash.data, hash->u.hash.length, NULL);
} else if (opt_auth_mode == AUTH_MODE_CERT ||
opt_auth_mode == AUTH_MODE_HYBRID) {
-#ifdef OPENSSL_GPL_VIOLATION
-
- /* BEGIN - check the signature using OpenSSL */
-
- X509 *x509;
- EVP_PKEY *pkey;
- RSA *rsa;
- X509_STORE *store;
- /* X509_LOOKUP *lookup; */
- X509_STORE_CTX *verify_ctx;
- unsigned char *rec_hash;
- int decr_size;
-
hex_dump("received signature", sig->u.sig.data, sig->u.sig.length, NULL);
- OpenSSL_add_all_ciphers();
- OpenSSL_add_all_digests();
- OpenSSL_add_all_algorithms();
-
- ERR_load_crypto_strings();
-
- hex_dump("last cert", last_cert->u.cert.data, last_cert->u.cert.length, NULL);
- x509 = d2i_X509(NULL, (const unsigned char **)&last_cert->u.cert.data, last_cert->u.cert.length);
- if (x509 == NULL) {
- ERR_print_errors_fp (stderr);
- error(1, 0, "x509 error\n");
- }
- DEBUG(3, printf("Subject name hash: %08lx\n",X509_subject_name_hash(x509)));
-
- /* BEGIN - verify certificate chain */
- /* create the cert store */
- if (!(store = X509_STORE_new())) {
- error(1, 0, "Error creating X509_STORE object\n");
- }
- /* load the CA certificates */
- if (X509_STORE_load_locations (store, config[CONFIG_CA_FILE], config[CONFIG_CA_DIR]) != 1) {
- error(1, 0, "Error loading the CA file or directory\n");
- }
- if (X509_STORE_set_default_paths (store) != 1) {
- error(1, 0, "Error loading the system-wide CA certificates\n");
- }
-
-#if 0
- /* check CRLs */
- /* add the corresponding CRL for each CA in the chain to the lookup */
-#define CRL_FILE "root-ca-crl.crl.pem"
-
- if (!(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()))) {
- error(1, 0, "Error creating X509 lookup object.\n");
- }
- if (X509_load_crl_file(lookup, CRL_FILE, X509_FILETYPE_PEM) != 1) {
- ERR_print_errors_fp(stderr);
- error(1, 0, "Error reading CRL file\n");
- }
- X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
-#endif /* 0 */
- /* create a verification context and initialize it */
- if (!(verify_ctx = X509_STORE_CTX_new ())) {
- error(1, 0, "Error creating X509_STORE_CTX object\n");
- }
- /* X509_STORE_CTX_init did not return an error condition
- in prior versions */
- if (X509_STORE_CTX_init (verify_ctx, store, x509, cert_stack) != 1)
- printf("Error intializing verification context\n");
-
- /* verify the certificate */
- if (X509_verify_cert(verify_ctx) != 1) {
- ERR_print_errors_fp(stderr);
- error(2, 0, "Error verifying the certificate-chain\n");
- } else
- DEBUG(3, printf("Certificate-chain verified correctly!\n"));
-
- /* END - verify certificate chain */
-
-
- /* BEGIN - Signature Verification */
- pkey = X509_get_pubkey(x509);
- if (pkey == NULL) {
- ERR_print_errors_fp (stderr);
- exit (1);
- }

- rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa == NULL) {
- ERR_print_errors_fp (stderr);
- exit (1);
- }
- rec_hash = xallocc(s->ike.md_len);
- decr_size = RSA_public_decrypt(sig->u.sig.length, sig->u.sig.data, rec_hash, rsa, RSA_PKCS1_PADDING);
-
- if (decr_size != (int) s->ike.md_len) {
- printf("Decrypted-Size: %d\n",decr_size);
+ ret = crypto_verify_chain(cctx,
+ config[CONFIG_CA_FILE],
+ config[CONFIG_CA_DIR],
+ &crerr);
+ if (ret)
+ crypto_call_error(crerr);
+
+ /* Verify signature */
+ rec_hash = crypto_decrypt_signature (cctx,
+ sig->u.sig.data,
+ sig->u.sig.length,
+ &decr_size,
+ CRYPTO_PAD_PKCS1,
+ &crerr);
+ if (!rec_hash)
+ crypto_call_error(crerr);
+
+ if (decr_size != s->ike.md_len) {
+ printf("Decrypted-Size: %lu\n",decr_size);
hex_dump(" decr_hash", rec_hash, decr_size, NULL);
hex_dump("expected hash", expected_hash, s->ike.md_len, NULL);

error(2, 0, "The hash-value, which was decrypted from the received signature, and the expected hash-value differ in size.\n");
} else {
if (memcmp(rec_hash, expected_hash, decr_size) != 0) {
- printf("Decrypted-Size: %d\n",decr_size);
+ printf("Decrypted-Size: %lu\n",decr_size);
hex_dump(" decr_hash", rec_hash, decr_size, NULL);
hex_dump("expected hash", expected_hash, s->ike.md_len, NULL);

@@ -1811,11 +1737,7 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
}
/* END - Signature Verification */

- EVP_PKEY_free(pkey);
free(rec_hash);
-
- /* END - check the signature using OpenSSL */
-#endif /* OPENSSL_GPL_VIOLATION */
}

gcry_md_close(hm);
@@ -1953,6 +1875,7 @@ static void do_phase1_am_packet2(struct sa_block *s, const char *shared_key)
}

gcry_md_close(skeyid_ctx);
+ crypto_ctx_free(cctx);
free(dh_shared_secret);

/* Determine presence of NAT */
@@ -2030,17 +1953,6 @@ static void do_phase1_am_packet3(struct sa_block *s)
uint8_t *p2kt;
size_t p2kt_len;
struct isakmp_payload *pl;
-#if 0 /* cert support */
-#ifdef OPENSSL_GPL_VIOLATION
- struct isakmp_payload *last_cert = NULL;
- struct isakmp_payload *sig = NULL;
-
-
- X509 *current_cert;
- /* structure to store the certificate chain */
- STACK_OF(X509) *cert_stack = sk_X509_new_null();
-#endif /* OPENSSL_GPL_VIOLATION */
-#endif /* 0 */

p2 = new_isakmp_packet();
memcpy(p2->i_cookie, s->ike.i_cookie, ISAKMP_COOKIE_LENGTH);

_______________________________________________
vpnc-devel mailing list
vpnc-devel [at] unix-ag
https://lists.unix-ag.uni-kl.de/mailman/listinfo/vpnc-devel
http://www.unix-ag.uni-kl.de/~massar/vpnc/


jmvpnc at loplof

Aug 14, 2009, 2:05 AM

Post #2 of 5 (944 views)
Permalink
Re: [PATCH v3] modularize certificate code + gnutls support [In reply to]

On Wed, Aug 12, 2009 at 01:34:27PM -0500, Dan Williams wrote:
> vpnc currently requires openssl to provide the hybrid auth mode. That's
> not ideal, since vpnc doesn't not include the OpenSSL exception in its
> license, meaning many distributions cannot ship a hybrid-auth-enabled
> vpnc.
>
> This patch splits out the certificate handing functions into a more
> modular framework, and adds a gnutls implementation of certificate
> handling bits, including testcases to ensure things work as expected.
> Hybrid-auth with gnutls is the default mode now, since vpnc has no
> licensing problem with gnutls. That means everyone gets hybrid FTW.
>
> Patch against current trunk. Also available here:
>
> http://people.redhat.com/dcbw/vpnc-hybrid-gnutls.patch
>
> Mostly by Dan Williams <dcbw [at] redhat>
> gnutls padding fixes by Laurent Goujon <laurent.goujon [at] online>

OK, that patch was finally enough to wake me up from doing other important/
interesting/... things.

I've done a cursory review of the patch and will review it with Maurice later
today if time permits.

As a short term thing I think the modularization is fine, but I have one
question not to Dan but everone out there *building* vpnc:
Is there any real reason to keep the openssl implementation for longer than a
short transition period?

Thanks already!
Joerg
--
Joerg Mayer <jmayer [at] loplof>
We are stuck with technology when what we really want is just stuff that
works. Some say that should read Microsoft instead of technology.
_______________________________________________
vpnc-devel mailing list
vpnc-devel [at] unix-ag
https://lists.unix-ag.uni-kl.de/mailman/listinfo/vpnc-devel
http://www.unix-ag.uni-kl.de/~massar/vpnc/


dwmw2 at infradead

Aug 14, 2009, 2:18 AM

Post #3 of 5 (955 views)
Permalink
Re: [PATCH v3] modularize certificate code + gnutls support [In reply to]

On Fri, 2009-08-14 at 11:05 +0200, Joerg Mayer wrote:
> On Wed, Aug 12, 2009 at 01:34:27PM -0500, Dan Williams wrote:
> > vpnc currently requires openssl to provide the hybrid auth mode. That's
> > not ideal, since vpnc doesn't not include the OpenSSL exception in its
> > license, meaning many distributions cannot ship a hybrid-auth-enabled
> > vpnc.
> >
> > This patch splits out the certificate handing functions into a more
> > modular framework, and adds a gnutls implementation of certificate
> > handling bits, including testcases to ensure things work as expected.
> > Hybrid-auth with gnutls is the default mode now, since vpnc has no
> > licensing problem with gnutls. That means everyone gets hybrid FTW.
> >
> > Patch against current trunk. Also available here:
> >
> > http://people.redhat.com/dcbw/vpnc-hybrid-gnutls.patch
> >
> > Mostly by Dan Williams <dcbw [at] redhat>
> > gnutls padding fixes by Laurent Goujon <laurent.goujon [at] online>
>
> OK, that patch was finally enough to wake me up from doing other important/
> interesting/... things.
>
> I've done a cursory review of the patch and will review it with Maurice later
> today if time permits.
>
> As a short term thing I think the modularization is fine, but I have one
> question not to Dan but everone out there *building* vpnc:
> Is there any real reason to keep the openssl implementation for longer than a
> short transition period?

If you plan to support authentication using client certificates, you
might want to keep it around a little longer -- OpenSSL works with
certificates stored in a TPM, which some corporations like to insist on.
I don't believe GNUTLS has that capability.

Although it would be lovely if GNUTLS was some day going to become a
full replacement for OpenSSL...

--
David Woodhouse Open Source Technology Centre
David.Woodhouse [at] intel Intel Corporation

_______________________________________________
vpnc-devel mailing list
vpnc-devel [at] unix-ag
https://lists.unix-ag.uni-kl.de/mailman/listinfo/vpnc-devel
http://www.unix-ag.uni-kl.de/~massar/vpnc/


jmvpnc at loplof

Aug 19, 2009, 1:36 AM

Post #4 of 5 (925 views)
Permalink
Re: [PATCH v3] modularize certificate code + gnutls support [In reply to]

On Fri, Aug 14, 2009 at 11:05:02AM +0200, Joerg Mayer wrote:
> OK, that patch was finally enough to wake me up from doing other important/
> interesting/... things.
>
> I've done a cursory review of the patch and will review it with Maurice later
> today if time permits.

OK, that didn't work out but I'm ready to do the commit - except for
the missing test-crypto.c in the patch. Can you please send that file?

Thanks
Joerg
--
Joerg Mayer <jmayer [at] loplof>
We are stuck with technology when what we really want is just stuff that
works. Some say that should read Microsoft instead of technology.

_______________________________________________
vpnc-devel mailing list
vpnc-devel [at] unix-ag
https://lists.unix-ag.uni-kl.de/mailman/listinfo/vpnc-devel
http://www.unix-ag.uni-kl.de/~massar/vpnc/


dcbw at redhat

Aug 19, 2009, 8:37 AM

Post #5 of 5 (925 views)
Permalink
Re: [PATCH v3] modularize certificate code + gnutls support [In reply to]

On Wed, 2009-08-19 at 10:36 +0200, Joerg Mayer wrote:
> On Fri, Aug 14, 2009 at 11:05:02AM +0200, Joerg Mayer wrote:
> > OK, that patch was finally enough to wake me up from doing other important/
> > interesting/... things.
> >
> > I've done a cursory review of the patch and will review it with Maurice later
> > today if time permits.
>
> OK, that didn't work out but I'm ready to do the commit - except for
> the missing test-crypto.c in the patch. Can you please send that file?

Sure, sorry. Inline and attached. Must have slipped through my
git-ization of the svn repo when I was doing the patch update. Let me
know if there's anything else you need.

Thanks!
Dan

----

/* IPSec VPN client compatible with Cisco equipment.

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.

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.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "crypto.h"

int main(int argc, char *argv[])
{
crypto_ctx *cctx;
crypto_error *error = NULL;
int i;
unsigned char *data;
size_t size = 0;
const unsigned char sig_data[] = {
0x30, 0x82, 0x04, 0xb5, 0x30, 0x82, 0x03, 0x9d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30,
0x81, 0x9f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x09, 0x42, 0x65, 0x72, 0x6b, 0x73, 0x68,

0x69, 0x72, 0x65, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x4e, 0x65,
0x77, 0x62, 0x75, 0x72, 0x79, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e,
0x4d, 0x79, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11,
0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x08, 0x54, 0x68, 0x65, 0x20, 0x55, 0x6e, 0x69,

0x74, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x74, 0x65, 0x73, 0x74,
0x2e, 0x73, 0x6f, 0x6d, 0x65, 0x77, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x21,
0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x74,
0x65, 0x73, 0x74, 0x40, 0x73, 0x6f, 0x6d, 0x65, 0x77, 0x68, 0x65, 0x72, 0x65, 0x2e, 0x6f, 0x72,

0x67, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x39, 0x30, 0x34, 0x32, 0x38, 0x30, 0x32, 0x35, 0x30, 0x35,
0x32, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30, 0x34, 0x32, 0x36, 0x30, 0x32, 0x35, 0x30, 0x35, 0x32,
0x5a, 0x30, 0x81, 0x8f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
0x53, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x09, 0x42, 0x65, 0x72, 0x6b,
};
const unsigned char dec_data[] = {
0x7c, 0x2a, 0xe4, 0x60, 0x10, 0x9f, 0xab, 0xd6, 0x76, 0x7b, 0x9d, 0x16, 0xbb, 0xd3, 0x16, 0xa3,
0x61, 0x50, 0x56, 0x13, 0xe4, 0x61, 0x0e, 0x90, 0x71, 0x5c, 0x47, 0xae, 0x4a, 0xc2, 0x89, 0xf8,
0x47, 0x61, 0x4c, 0x3f, 0xd6, 0x11, 0x97, 0xb7, 0x0d, 0x84, 0x86, 0xdd, 0xe9, 0x6d, 0x3e, 0x89,
0xe0, 0x4f, 0x7a, 0x95, 0x3f, 0x6e, 0xe4, 0xcd, 0xb2, 0x80, 0x3e, 0x19, 0x3e, 0x97, 0x7c, 0xdf,
0xd5, 0xff, 0xcb, 0x90, 0xfb, 0x71, 0x9c, 0xef, 0xa1, 0xf6, 0x8c, 0x36, 0xb3, 0x1f, 0x63, 0x7f,
0x32, 0xf5, 0x00, 0x12, 0x5e, 0x13, 0x84, 0x88, 0xe3, 0x13, 0x1c, 0x11, 0x2d, 0x9a, 0xd7, 0xec,
0x51, 0x94, 0x20, 0x6e, 0x8f, 0x69, 0xdf, 0x07, 0xe9, 0x46, 0x3b, 0xd9, 0x1c, 0x0a, 0xc0, 0x60,
0x90, 0x3a, 0x9a, 0x18, 0xa8, 0x19, 0xc6, 0x78, 0xc9, 0xf3, 0x1a, 0xbb, 0xca, 0xa8, 0xb5, 0x05,
0x6b, 0xa8, 0xfb, 0xeb, 0xdd, 0x19, 0x56, 0xc4, 0xfe, 0x7c, 0x84, 0xb1, 0xfd, 0x92, 0xbd, 0xe2,
0xb2, 0x94, 0x57, 0x3d, 0x03, 0x0a, 0xf1, 0xee, 0xca, 0xec, 0x8a, 0x0f, 0xb6, 0x23, 0x0b, 0x44,
0x14, 0x0d, 0xe0, 0xb1, 0x68, 0x38, 0x56, 0x7c, 0x66, 0x60, 0x8f, 0x54, 0x8b, 0x5c, 0x80, 0x37,
0x94, 0x27, 0x89, 0x47, 0x2c, 0x24, 0x45, 0x6b, 0x76, 0xdd, 0xfb, 0xf1, 0x31, 0xef, 0x7f, 0xa4,
0xba, 0x95, 0x4b, 0x91, 0x9c, 0x86, 0xa6, 0x48, 0xa2, 0x5a, 0x41, 0x64, 0x31, 0x14, 0x80, 0x6b,
0xb3, 0x0d, 0x46, 0x14, 0xb2, 0x61, 0x49, 0x81, 0xf5, 0x14, 0x2e, 0x1c, 0x3b, 0x7b, 0xc2, 0x23,
0x9d, 0x31, 0x66, 0x49, 0x56, 0x50, 0x69, 0x69, 0x5a, 0x5c, 0x82, 0x68, 0x96, 0x04, 0xc1, 0x76,
0x18, 0x19, 0x13, 0x95, 0xad, 0xbd, 0x5f, 0x96, 0x6d, 0xfe, 0xde, 0x65, 0x6a, 0x78, 0x47, 0x63,
};

if (argc < 4) {
fprintf(stderr, "Need at least 3 arguments: <ca> <cert1> <server>\n");
return 1;
}

cctx = crypto_ctx_new(&error);
if (!cctx) {
fprintf(stderr, "Error initializing crypto: %s\n", error->msg);
return error->code;
}

/* Load certificates */
for (i = 2; i < argc; i++) {
data = crypto_read_cert(argv[i], &size, &error);
if (!data) {
fprintf(stderr, "Error reading cert %d: %s\n", i + 1, error->msg);
return error->code;
}
if (crypto_push_cert(cctx, data, size, &error)) {
free(data);
fprintf(stderr, "Error pushing cert %d: %s\n", i + 1, error->msg);
return error->code;
}
free(data);
}

/* Verify the cert chain */
if (crypto_verify_chain(cctx, argv[1], NULL, &error) != 0) {
fprintf(stderr, "Error verifying chain: %s\n", error && error->msg ? error->msg : "(none)");
return error->code;
}

/* Decrypt something using the public key of the server certificate */
size = 0;
data = crypto_decrypt_signature(cctx, &sig_data[0], sizeof(sig_data), &size, CRYPTO_PAD_NONE, &error);
if (!data || !size) {
fprintf(stderr, "Error decrypting signature: %s\n", error && error->msg ? error->msg : "(none)");
return error->code;
}

if (size != sizeof(dec_data)) {
fprintf(stderr, "Error decrypting signature: unexpected "
"decrypted size %lu (expected %lu)\n", size, sizeof(dec_data));
return 1;
}

if (memcmp(data, dec_data, sizeof(dec_data))) {
fprintf(stderr, "Error decrypting signature: decrypted data did"
" not match expected decrypted data\n");
return 1;
}
free(data);

fprintf(stdout, "Success\n");

crypto_ctx_free(cctx);
return 0;
}
Attachments: test-crypto.c (5.84 KB)

vpnc devel RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.