diff --git a/Makefile b/Makefile index 920bd18..633ad7c 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 2e7caa0..6bab051 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..35885ff --- /dev/null +++ b/crypto-gnutls.c @@ -0,0 +1,477 @@ +/* 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 +#include +#include +#include +#include + +#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; +} + +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 *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, dec_mpi = NULL; + size_t 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; + } + + switch (padding) { + case CRYPTO_PAD_NONE: + err = gcry_sexp_build(&sig, NULL, "(data (flags raw) (value %b))", sig_len, sig_data); + break; + case CRYPTO_PAD_PKCS1: + err = gcry_sexp_build(&sig, NULL, "(data (flags pkcs1) (value %b))", sig_len, sig_data); + break; + default: + crypto_error_set(error, 1, 0, "unknown padding mechanism %d", padding); + goto out; + } + + 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, &rec_hash, &hash_len, dec_mpi); + if (!rec_hash) + crypto_error_set(error, 1, 0, "could not get extract decrypted signature"); + else + *out_len = (int) hash_len; + +out: + 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 (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 +#include + +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 +#include +#include +#include +#include +#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 +#include + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +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/test-crypto.c b/test-crypto.c new file mode 100644 index 0000000..05c1322 --- /dev/null +++ b/test-crypto.c @@ -0,0 +1,133 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#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: \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; +} + diff --git a/test/cert0.crt b/test/cert0.crt new file mode 100644 index 0000000..1d9d811 Binary files /dev/null and b/test/cert0.crt differ 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.crt b/test/cert1.crt new file mode 100644 index 0000000..2e471d4 Binary files /dev/null and b/test/cert1.crt differ 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.crt b/test/cert2.crt new file mode 100644 index 0000000..6ae0a55 Binary files /dev/null and b/test/cert2.crt differ 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.crt b/test/root.crt new file mode 100644 index 0000000..77e783a Binary files /dev/null and b/test/root.crt differ 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 44cbe65..a1f6bce 100644 --- a/vpnc.c +++ b/vpnc.c @@ -40,12 +40,7 @@ #include -#ifdef OPENSSL_GPL_VIOLATION -/* OpenSSL */ -#include -#include -#endif /* OPENSSL_GPL_VIOLATION */ - +#include "crypto.h" #include "sysdep.h" #include "config.h" #include "isakmp-pkt.h" @@ -1297,24 +1295,23 @@ static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_b DEBUGTOP(2, printf("S4.4 AM_packet2\n")); /* Decode the recieved packet. */ { - int reject; + int reject, ret; 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; unsigned char *psk_skeyid; unsigned char *skeyid; gcry_md_hd_t skeyid_ctx; + 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); @@ -1472,14 +1469,15 @@ static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_b 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: @@ -1667,10 +1665,11 @@ static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_b /* Verify the hash. */ { gcry_md_hd_t hm; - unsigned char *expected_hash; + unsigned char *expected_hash, *rec_hash; uint8_t *sa_f, *idi_f, *idp_f; size_t sa_size, idi_size, idp_size; struct isakmp_payload *sa, *idi; + size_t decr_size = 0; sa = p1->payload; for (idi = sa; idi->type != ISAKMP_PAYLOAD_ID; idi = idi->next) ; @@ -1698,119 +1697,42 @@ static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_b 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); - + error(2, 0, "The hash-value, which was decrypted from the received signature, and the expected hash-value differ.\n"); } else { DEBUG(3, printf("Signature MATCH!!\n")); } } - /* END - Signature Verification */ - - EVP_PKEY_free(pkey); free(rec_hash); - - /* END - check the signature using OpenSSL */ -#endif /* OPENSSL_GPL_VIOLATION */ } gcry_md_close(hm); @@ -1946,6 +1868,7 @@ static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_b } gcry_md_close(skeyid_ctx); + crypto_ctx_free(cctx); } DEBUGTOP(2, printf("S4.5 AM_packet3\n")); @@ -1955,17 +1878,6 @@ static void do_phase1_am(const char *key_id, const char *shared_key, struct sa_b 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);