From 00d9ca3aaa56c083cfbb051235f3bdcbe6c8c253 Mon Sep 17 00:00:00 2001 From: pixdamix Date: Thu, 5 Nov 2009 08:46:33 +0000 Subject: [PATCH] Add pathfinder support for certificate validation From http://code.google.com/p/pathfinder-pki/ PathFinder is designed to provide a mechanism for any program to perform RFC3280-compliant path validation of X509 certificates, even when some of the intermediate certificates are not present on the local machine. By design, Pathfinder automatically downloads any such certificates from the Internet as needed using the AIA and CRL distribution point extensions of the certificates it is processing. It has the ability to do revocation status checking either using CRL or OCSP, or both. And, given the recent vulnerabilities that have rendered the MD5 algorithm highly suspect, it allows the administrator to choose to not validate certificates using that algorithm anywhere in the trust path. git-svn-id: http://opkg.googlecode.com/svn/trunk@261 e8e0d7a0-c8d9-11dd-a880-a1081c7ac358 --- Makefile.am | 3 ++ configure.ac | 20 +++++++- libopkg/Makefile.am | 9 ++-- libopkg/opkg_download.c | 22 +++++++++ libopkg/opkg_pathfinder.c | 99 +++++++++++++++++++++++++++++++++++++++ libopkg/opkg_pathfinder.h | 32 +++++++++++++ 6 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 libopkg/opkg_pathfinder.c create mode 100644 libopkg/opkg_pathfinder.h diff --git a/Makefile.am b/Makefile.am index a746e60..b1980bf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,6 +5,9 @@ BUILD_CPU=@build_cpu@ OPKGLIBDIR=@opkglibdir@ ALL_CFLAGS=-g -O -Wall -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DDATADIR=\"@datadir@\" +PATHFINDER_CFLAGS = @PATHFINDER_CFLAGS@ +PATHFINDER_LIBS = @PATHFINDER_LIBS@ + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libopkg.pc diff --git a/configure.ac b/configure.ac index 95233b5..df58817 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,22 @@ AC_PROG_LIBTOOL # Checks for libraries +dnl extra argument: --with-pathfinder +AC_ARG_ENABLE(pathfinder, + AC_HELP_STRING([--with-pathfinder], [With libpathfinder support. + [[default=no]] ]), + [want_pathfinder="$enableval"], [want_pathfinder="no"]) +dnl Check for libpathfinder +if test "x$want_pathfinder" = "xyes"; then + PKG_CHECK_MODULES([PATHFINDER], [pathfinder-openssl dbus-1 openssl]) + if test -n "$PATHFINDER_CFLAGS$PATHFINDER_LIBS"; then + AC_DEFINE(HAVE_PATHFINDER, 1, [we have pathfinder]) + fi + AC_SUBST(PATHFINDER_CFLAGS) + AC_SUBST(PATHFINDER_LIBS) +fi +AM_CONDITIONAL(HAVE_PATHFINDER, test "x$want_pathfinder" = "xyes") + # check for libcurl AC_ARG_ENABLE(curl, AC_HELP_STRING([--enable-curl], [Enable downloading with curl @@ -36,7 +52,7 @@ AC_ARG_ENABLE(curl, [want_curl="$enableval"], [want_curl="yes"]) if test "x$want_curl" = "xyes"; then - PKG_CHECK_MODULES(CURL, libcurl) + PKG_CHECK_MODULES(CURL, [libcurl]) AC_DEFINE(HAVE_CURL, 1, [Define if you want CURL support]) fi @@ -65,7 +81,7 @@ fi # check for libssl-curl AC_ARG_ENABLE(ssl-curl, AC_HELP_STRING([--enable-ssl-curl], [Enable certificate authentication with curl - [[default="$default_sslcurl"]] ]), + [[default="yes"]] ]), [want_sslcurl="$enableval"], [want_sslcurl="yes"]) if test "x$want_curl" = "xyes" -a "x$want_sslcurl" = "xyes"; then diff --git a/libopkg/Makefile.am b/libopkg/Makefile.am index 5aee171..067d867 100644 --- a/libopkg/Makefile.am +++ b/libopkg/Makefile.am @@ -1,5 +1,5 @@ -AM_CFLAGS=-Wall -Werror -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) +AM_CFLAGS=-Wall -Werror -DHOST_CPU_STR=\"@host_cpu@\" -DBUILD_CPU=@build_cpu@ -DLIBDIR=\"@libdir@\" -DOPKGLIBDIR=\"@opkglibdir@\" -DOPKGETCDIR=\"@opkgetcdir@\" -DDATADIR=\"@datadir@\" -I$(top_srcdir) $(BIGENDIAN_CFLAGS) $(CURL_CFLAGS) $(GPGME_CFLAGS) $(PATHFINDER_CFLAGS) libopkg_includedir=$(includedir)/libopkg libopkg_include_HEADERS= opkg.h @@ -29,7 +29,9 @@ opkg_list_sources = conffile.c conffile.h conffile_list.c conffile_list.h \ opkg_util_sources = file_util.c file_util.h opkg_message.h opkg_message.c md5.c md5.h \ sprintf_alloc.c sprintf_alloc.h str_util.c str_util.h \ xregex.c xregex.h xsystem.c xsystem.h - +if HAVE_PATHFINDER +opkg_util_sources += opkg_pathfinder.c opkg_pathfinder.h +endif if HAVE_SHA256 opkg_util_sources += sha256.c sha256.h endif @@ -40,7 +42,8 @@ libopkg_la_SOURCES = \ $(opkg_cmd_sources) $(opkg_db_sources) \ $(opkg_util_sources) $(opkg_list_sources) -libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) +libopkg_la_LIBADD = $(top_builddir)/libbb/libbb.la $(CURL_LIBS) $(GPGME_LIBS) $(OPENSSL_LIBS) $(PATHFINDER_LIBS) + # make sure we only export symbols that are for public use libopkg_la_LDFLAGS = -export-symbols-regex "^opkg_.*" diff --git a/libopkg/opkg_download.c b/libopkg/opkg_download.c index 77dc8e4..0e67927 100644 --- a/libopkg/opkg_download.c +++ b/libopkg/opkg_download.c @@ -26,6 +26,7 @@ #include #include #include +#include #endif #if defined(HAVE_GPGME) @@ -49,6 +50,10 @@ #include "opkg_defines.h" #include "libbb/libbb.h" +#ifdef HAVE_PATHFINDER +#include "opkg_pathfinder.h" +#endif + #if defined(HAVE_OPENSSL) || defined(HAVE_SSLCURL) static void openssl_init(void); #endif @@ -413,6 +418,13 @@ opkg_verify_file (opkg_conf_t *conf, char *text_file, char *sig_file) "Can't read signature file (Corrupted ?)\n"); goto verify_file_end; } +#if defined(HAVE_PATHFINDER) + if(!pkcs7_pathfinder_verify_signers(p7)){ + opkg_message(conf, OPKG_ERROR, "pkcs7_pathfinder_verify_signers: " + "Path verification failed\n"); + } + +#endif // Open the Package file to authenticate if (!(indata = BIO_new_file(text_file, "rb"))){ @@ -595,6 +607,16 @@ static CURL *opkg_curl_init(opkg_conf_t *conf, curl_progress_func cb, void *data * CURLOPT_SSL_VERIFYPEER default is nonzero (curl => 7.10) */ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + }else{ +#ifdef HAVE_PATHFINDER + if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, curl_ssl_ctx_function) != CURLE_OK){ + opkg_message(conf, OPKG_DEBUG, "Failed to set ssl path verification callback\n"); + }else{ + curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, NULL); + } + + //curl_easy_setopt(curl, CURLOPT_SSL_CERT_VERIFY_FUNCTION, curlcb_pathfinder); +#endif } /* certification authority file and/or path */ diff --git a/libopkg/opkg_pathfinder.c b/libopkg/opkg_pathfinder.c new file mode 100644 index 0000000..793c3a4 --- /dev/null +++ b/libopkg/opkg_pathfinder.c @@ -0,0 +1,99 @@ +/* vi: set noexpandtab sw=4 sts=4: */ +/* opkg_download.c - the opkg package management system + + Carl D. Worth + + Copyright (C) 2001 University of Southern California + Copyright (C) 2008 OpenMoko Inc + + 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, 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. +*/ +#include "config.h" + +#include +#include +#include "includes.h" +#include "opkg_message.h" + +#if defined(HAVE_SSLCURL) +#include +#endif + +#if defined(HAVE_SSLCURL) || defined(HAVE_OPENSSL) +/* + * This callback is called instead of X509_verify_cert to perform path + * validation on a certificate using pathfinder. + * + */ +static int pathfinder_verify_callback(X509_STORE_CTX *ctx, void *arg) +{ + char *errmsg; + const char *hex = "0123456789ABCDEF"; + size_t size = i2d_X509(ctx->cert, NULL); + unsigned char *keybuf, *iend; + iend = keybuf = malloc(size); + i2d_X509(ctx->cert, &iend); + char *certdata_str = malloc(size * 2 + 1); + unsigned char *cp = keybuf; + char *certdata_str_i = certdata_str; + while (cp < iend) + { + unsigned char ch = *cp++; + *certdata_str_i++ = hex[(ch >> 4) & 0xf]; + *certdata_str_i++ = hex[ch & 0xf]; + } + *certdata_str_i = 0; + free(keybuf); + + const char *policy = "2.5.29.32.0"; // anyPolicy + int validated = pathfinder_dbus_verify(certdata_str, policy, 0, 0, &errmsg); + + if (!validated) + fprintf(stderr, "curlcb_pathfinder: Path verification failed: %s", errmsg); + + free(certdata_str); + free(errmsg); + + return validated; +} +#endif + + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7) +{ + STACK_OF(X509) *signers; + int i; + + signers = PKCS7_get0_signers(p7, NULL, 0); + + for(i = 0; i < sk_X509_num(signers); i++){ + X509_STORE_CTX ctx = { + .cert = sk_X509_value(signers, i), + }; + + if(!pathfinder_verify_callback(&ctx, NULL)) + return 0; + } + + return 1; +} +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm) { + + SSL_CTX * ctx = (SSL_CTX *) sslctx; + SSL_CTX_set_cert_verify_callback(ctx, pathfinder_verify_callback, parm); + + return CURLE_OK ; +} +#endif diff --git a/libopkg/opkg_pathfinder.h b/libopkg/opkg_pathfinder.h new file mode 100644 index 0000000..446d861 --- /dev/null +++ b/libopkg/opkg_pathfinder.h @@ -0,0 +1,32 @@ +/* opkg_download.h - the opkg package management system + + Camille Moncelier + + Copyright (C) 2009 Camille Moncelier + + 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, 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. +*/ + +#ifndef OPKG_PATHFINDER_H +#define OPKG_PATHFINDER_H + +#include "config.h" + +#if defined(HAVE_OPENSSL) +int pkcs7_pathfinder_verify_signers(PKCS7* p7); +#endif + +#if defined(HAVE_SSLCURL) +CURLcode curl_ssl_ctx_function(CURL * curl, void * sslctx, void * parm); +#endif + + +#endif -- 2.25.1