summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-05-08 13:24:20 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2008-05-08 13:24:20 +0200
commit3d74096021d95a5073c4d208cc2e31375bd237a1 (patch)
treeeeffd5c0388797c42dea1cca103dec54639d81f3
parent664f7cab3f667cdda1c131b188f52ef1bac4c049 (diff)
downloadrsyslog-3d74096021d95a5073c4d208cc2e31375bd237a1.tar.gz
rsyslog-3d74096021d95a5073c4d208cc2e31375bd237a1.tar.xz
rsyslog-3d74096021d95a5073c4d208cc2e31375bd237a1.zip
added a bit of doc (at least something...)
-rw-r--r--runtime/nsd_gtls.c234
-rw-r--r--runtime/nsdsel_gtls.c4
-rw-r--r--runtime/rsyslog.h1
-rwxr-xr-xtools/gnutls/cert-gen-selfsigned3
-rwxr-xr-xtools/gnutls/cert-show-fingerprint4
5 files changed, 245 insertions, 1 deletions
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index bd97254d..799992fe 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -23,10 +23,12 @@
* A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
#include <gcrypt.h>
#include <errno.h>
@@ -67,9 +69,192 @@ static int bGlblSrvrInitDone = 0; /**< 0 - server global init not yet done, 1 -
/* ------------------------------ GnuTLS specifics ------------------------------ */
+////////////////// experimental ///////////////////
+uchar *gtlsStrerror(int error);
+static const char* bin2hex(void* bin, size_t bin_size)
+{
+ static char printable[170];
+ uchar *_bin = bin;
+ char* print;
+ size_t i;
+
+ if (bin_size > 50) bin_size = 50;
+
+ print = printable;
+ for(i = 0; i < bin_size; i++) {
+ sprintf(print, "%2.2X:", _bin[i]);
+ print += 3;
+ }
+
+ return printable;
+}
+
+#if 0
+/* This function will print information about this session's peer
+ * certificate.
+ */
+static rsRetVal
+print_x509_certificate_info(gnutls_session session)
+{
+ char fingerprint[20];
+ char serial[40];
+ char dn[128];
+ size_t size;
+ unsigned int algo, bits;
+ time_t expiration_time, activation_time;
+ const gnutls_datum *cert_list;
+ int cert_list_size = 0;
+ gnutls_x509_crt cert;
+ int gnuRet;
+ DEFiRet;
+
+ /* This function only works for X.509 certificates.
+ */
+ if(gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
+ return RS_RET_TLS_CERT_ERR;
+
+ cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
+
+ dbgprintf("Peer provided %d certificates.\n", cert_list_size);
+
+ if(cert_list_size > 0) {
+ /* we only print information about the first certificate */
+ gnutls_x509_crt_init( &cert);
+
+ CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
+
+ dbgprintf("Certificate info:\n");
+
+ expiration_time = gnutls_x509_crt_get_expiration_time(cert);
+ activation_time = gnutls_x509_crt_get_activation_time(cert);
+
+ dbgprintf("\tCertificate is valid since: %s", ctime(&activation_time));
+ dbgprintf("\tCertificate expires: %s", ctime(&expiration_time));
+
+ /* Print the serial number of the certificate */
+ size = sizeof(serial);
+ CHKgnutls(gnutls_x509_crt_get_serial(cert, serial, &size));
+ dbgprintf("\tCertificate serial number: %s\n", bin2hex( serial, size));
+
+ /* print the SHA1 fingerprint */
+ size = sizeof(fingerprint);
+ CHKgnutls(gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, fingerprint, &size));
+ dbgprintf("\tCertificate SHA1 fingerprint: %s\n", bin2hex(fingerprint, size));
+
+ /* Extract some of the public key algorithm's parameters
+ */
+ algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
+
+ dbgprintf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
+
+ /* Print the version of the X.509
+ * certificate.
+ */
+ dbgprintf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
+
+ size = sizeof(dn);
+ gnutls_x509_crt_get_dn( cert, dn, &size);
+ dbgprintf("\tDN: %s\n", dn);
+
+ size = sizeof(dn);
+ gnutls_x509_crt_get_issuer_dn( cert, dn, &size);
+ dbgprintf("\tIssuer's DN: %s\n", dn);
+
+ gnutls_x509_crt_deinit( cert);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+/* This function will print some details of the
+ * given session.
+ */
+int print_info(gnutls_session session)
+{
+ const char *tmp;
+ gnutls_credentials_type cred;
+ gnutls_kx_algorithm kx;
+
+ /* print the key exchange's algorithm name
+ */
+ kx = gnutls_kx_get(session);
+ tmp = gnutls_kx_get_name(kx);
+ dbgprintf("- Key Exchange: %s\n", tmp);
+
+ /* Check the authentication type used and switch
+ * to the appropriate.
+ */
+ cred = gnutls_auth_get_type(session);
+ switch (cred) {
+ case GNUTLS_CRD_ANON: /* anonymous authentication */
+ dbgprintf("- Anonymous DH using prime of %d bits\n",
+ gnutls_dh_get_prime_bits(session));
+ break;
+ case GNUTLS_CRD_CERTIFICATE: /* certificate authentication */
+ /* Check if we have been using ephemeral Diffie Hellman.
+ */
+ if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) {
+ dbgprintf("\n- Ephemeral DH using prime of %d bits\n",
+ gnutls_dh_get_prime_bits(session));
+ }
+
+ /* if the certificate list is available, then
+ * print some information about it.
+ */
+ print_x509_certificate_info(session);
+ break;
+ case GNUTLS_CRD_SRP: /* certificate authentication */
+ dbgprintf("GNUTLS_CRD_SRP/IA");
+ break;
+ case GNUTLS_CRD_PSK: /* certificate authentication */
+ dbgprintf("GNUTLS_CRD_PSK");
+ break;
+ case GNUTLS_CRD_IA: /* certificate authentication */
+ dbgprintf("GNUTLS_CRD_IA");
+ break;
+ } /* switch */
+
+ /* print the protocol's name (ie TLS 1.0) */
+ tmp = gnutls_protocol_get_name(gnutls_protocol_get_version(session));
+ dbgprintf("- Protocol: %s\n", tmp);
+
+ /* print the certificate type of the peer.
+ * ie X.509
+ */
+ tmp = gnutls_certificate_type_get_name(
+ gnutls_certificate_type_get(session));
+
+ dbgprintf("- Certificate Type: %s\n", tmp);
+
+ /* print the compression algorithm (if any)
+ */
+ tmp = gnutls_compression_get_name( gnutls_compression_get(session));
+ dbgprintf("- Compression: %s\n", tmp);
+
+ /* print the name of the cipher used.
+ * ie 3DES.
+ */
+ tmp = gnutls_cipher_get_name(gnutls_cipher_get(session));
+ dbgprintf("- Cipher: %s\n", tmp);
+
+ /* Print the MAC algorithms name.
+ * ie SHA1
+ */
+ tmp = gnutls_mac_get_name(gnutls_mac_get(session));
+ dbgprintf("- MAC: %s\n", tmp);
+
+ return 0;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////
static gnutls_certificate_credentials xcred;
static gnutls_dh_params dh_params;
+
/* a thread-safe variant of gnutls_strerror - TODO: implement it!
* The caller must free the returned string.
* rgerhards, 2008-04-30
@@ -142,7 +327,6 @@ finalize_it:
}
-
static rsRetVal
generate_dh_params(void)
{
@@ -191,6 +375,50 @@ finalize_it:
}
+/* check the fingerprint of the remote peer's certificate.
+ * rgerhards, 2008-05-08
+ */
+static rsRetVal
+gtlsChkFingerprint(nsd_gtls_t *pThis)
+{
+ char fingerprint[20];
+ size_t size;
+ const gnutls_datum *cert_list;
+ int cert_list_size = 0;
+ gnutls_x509_crt cert;
+ int gnuRet;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, nsd_gtls);
+
+ /* This function only works for X.509 certificates. */
+ if(gnutls_certificate_type_get(pThis->sess) != GNUTLS_CRT_X509)
+ return RS_RET_TLS_CERT_ERR;
+
+ cert_list = gnutls_certificate_get_peers(pThis->sess, &cert_list_size);
+
+ /* we always use only the first certificate. As of GnuTLS documentation, the
+ * first certificate always contains the remote peers own certificate. All other
+ * certificates are issuer's certificates (up the chain). However, we do not match
+ * against some issuer fingerprint but only ourselfs. -- rgerhards, 2008-05-08
+ */
+ if(cert_list_size > 0) {
+ CHKgnutls(gnutls_x509_crt_init(&cert));
+ CHKgnutls(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
+
+ /* obtain the SHA1 fingerprint */
+ size = sizeof(fingerprint);
+ CHKgnutls(gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, fingerprint, &size));
+ dbgprintf("\tCertificate SHA1 fingerprint: %s\n", bin2hex(fingerprint, size));
+
+ gnutls_x509_crt_deinit(cert);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
/* globally de-initialize GnuTLS */
static rsRetVal
gtlsGlblExit(void)
@@ -408,6 +636,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
} else if(gnuRet != 0) {
ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR);
}
+
pNew->iMode = 1; /* this session is now in TLS mode! */
*ppNew = (nsd_t*) pNew;
@@ -532,6 +761,9 @@ Connect(nsd_t *pNsd, int family, uchar *port, uchar *host)
CHKgnutls(gnutls_handshake(pThis->sess));
dbgprintf("GnuTLS handshake succeeded\n");
+ /* now check if the remote peer is permitted to talk to us */
+ CHKiRet(gtlsChkFingerprint(pThis));
+
finalize_it:
if(iRet != RS_RET_OK) {
if(pThis->bHaveSess) {
diff --git a/runtime/nsdsel_gtls.c b/runtime/nsdsel_gtls.c
index 8c1e705b..bdd73419 100644
--- a/runtime/nsdsel_gtls.c
+++ b/runtime/nsdsel_gtls.c
@@ -128,6 +128,10 @@ doRetry(nsd_gtls_t *pNsd)
switch(pNsd->rtryCall) {
case gtlsRtry_handshake:
gnuRet = gnutls_handshake(pNsd->sess);
+ if(gnuRet == 0) {
+ /* we got a handshake, now print session info */
+ print_info(pNsd->sess);
+ }
break;
default:
assert(0); /* this shall not happen! */
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index c32e190c..0be5d49a 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -222,6 +222,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_INVAID_DRVR_MODE = -2081, /**< tried to set mode not supported by driver */
RS_RET_DRVRNAME_TOO_LONG = -2082, /**< driver name too long - should never happen */
RS_RET_TLS_HANDSHAKE_ERR = -2083, /**< TLS handshake failed */
+ RS_RET_TLS_CERT_ERR = -2084, /**< generic TLS certificate error */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/tools/gnutls/cert-gen-selfsigned b/tools/gnutls/cert-gen-selfsigned
index 84e6e6d6..e1c25386 100755
--- a/tools/gnutls/cert-gen-selfsigned
+++ b/tools/gnutls/cert-gen-selfsigned
@@ -1,3 +1,6 @@
#/bin/sh
+# generates a self-signed certificate and key suitable for use with rsyslog
+# 2008-05-08, rgerhards
+# TODO: make this a robust shell script
certtool --generate-privkey --outfile $1-key.pem
certtool --generate-self-signed --load-privkey $1-key.pem --outfile $1-cert.pem
diff --git a/tools/gnutls/cert-show-fingerprint b/tools/gnutls/cert-show-fingerprint
index 1324ef1c..f61c6840 100755
--- a/tools/gnutls/cert-show-fingerprint
+++ b/tools/gnutls/cert-show-fingerprint
@@ -1,2 +1,6 @@
#/bin/sh
+# must be called with the certificate file as first parameter. Displays all
+# fingerprints for the first certificate.
+# 2008-05-08, rgerhards
+# TODO: make this a robust shell script
certtool -i < $1|grep Fingerprint