summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-05-08 16:00:57 +0200
committerRainer Gerhards <rgerhards@adiscon.com>2008-05-08 16:00:57 +0200
commitd594f83a893a517328f55b0b0b3240c4073efb89 (patch)
treee360029da448ca8b7f18e0b007695664b982b1aa
parent3d74096021d95a5073c4d208cc2e31375bd237a1 (diff)
downloadrsyslog-d594f83a893a517328f55b0b0b3240c4073efb89.tar.gz
rsyslog-d594f83a893a517328f55b0b0b3240c4073efb89.tar.xz
rsyslog-d594f83a893a517328f55b0b0b3240c4073efb89.zip
server's X509 cert fingerprint is obtained by client on connect
-rw-r--r--runtime/nsd_gtls.c234
-rw-r--r--runtime/nsdsel_gtls.c4
-rw-r--r--runtime/rsyslog.h1
3 files changed, 50 insertions, 189 deletions
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index 799992fe..03ceba7b 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -37,6 +37,7 @@
#include "module-template.h"
#include "cfsysline.h"
#include "obj.h"
+#include "stringbuf.h"
#include "errmsg.h"
#include "nsd_ptcp.h"
#include "nsdsel_gtls.h"
@@ -69,192 +70,41 @@ 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;
-}
+static gnutls_certificate_credentials xcred;
+static gnutls_dh_params dh_params;
-#if 0
-/* This function will print information about this session's peer
- * certificate.
+/* Convert a fingerprint to printable data. The conversion is carried out
+ * according IETF I-D syslog-transport-tls-12. The fingerprint string is
+ * returned in a new cstr object. It is the caller's responsibility to
+ * destruct that object.
+ * rgerhards, 2008-05-08
*/
static rsRetVal
-print_x509_certificate_info(gnutls_session session)
+GenFingerprintStr(uchar *pFingerprint, size_t sizeFingerprint, cstr_t **ppStr)
{
- 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;
+ cstr_t *pStr = NULL;
+ uchar buf[4];
+ size_t i;
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);
+ CHKiRet(rsCStrConstruct(&pStr));
+ for(i = 0 ; i < sizeFingerprint ; ++i) {
+ snprintf((char*)buf, sizeof(buf), "%2.2X:", pFingerprint[i]);
+ CHKiRet(rsCStrAppendStrWithLen(pStr, buf, 3));
}
+ CHKiRet(rsCStrFinish(pStr));
+
+ *ppStr = pStr;
finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pStr != NULL)
+ rsCStrDestruct(&pStr);
+ }
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
@@ -381,11 +231,13 @@ finalize_it:
static rsRetVal
gtlsChkFingerprint(nsd_gtls_t *pThis)
{
- char fingerprint[20];
+ cstr_t *pstrFingerprint = NULL;
+ uchar fingerprint[20];
size_t size;
const gnutls_datum *cert_list;
- int cert_list_size = 0;
+ unsigned int list_size = 0;
gnutls_x509_crt cert;
+ int bMustDeinitCert = 0;
int gnuRet;
DEFiRet;
@@ -395,26 +247,34 @@ gtlsChkFingerprint(nsd_gtls_t *pThis)
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);
+ cert_list = gnutls_certificate_get_peers(pThis->sess, &list_size);
+
+ if(list_size < 1)
+ ABORT_FINALIZE(RS_RET_TLS_NO_CERT);
- /* we always use only the first certificate. As of GnuTLS documentation, the
- * first certificate always contains the remote peers own certificate. All other
+ /* If we reach this point, we have at least one valid certificate.
+ * We always use only the first certificate. As of GnuTLS documentation, the
+ * first certificate always contains the remote peer's 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));
+ CHKgnutls(gnutls_x509_crt_init(&cert));
+ bMustDeinitCert = 1; /* indicate cert is initialized and must be freed on exit */
+ 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));
+ /* obtain the SHA1 fingerprint */
+ size = sizeof(fingerprint);
+ CHKgnutls(gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, fingerprint, &size));
+ CHKiRet(GenFingerprintStr(fingerprint, size, &pstrFingerprint));
+ dbgprintf("peer's certificate SHA1 fingerprint: %s\n", rsCStrGetSzStr(pstrFingerprint));
- gnutls_x509_crt_deinit(cert);
- }
finalize_it:
+ if(pstrFingerprint != NULL)
+ rsCStrDestruct(&pstrFingerprint);
+ if(bMustDeinitCert)
+ gnutls_x509_crt_deinit(cert);
+
RETiRet;
}
diff --git a/runtime/nsdsel_gtls.c b/runtime/nsdsel_gtls.c
index bdd73419..1ee4b46c 100644
--- a/runtime/nsdsel_gtls.c
+++ b/runtime/nsdsel_gtls.c
@@ -129,8 +129,8 @@ doRetry(nsd_gtls_t *pNsd)
case gtlsRtry_handshake:
gnuRet = gnutls_handshake(pNsd->sess);
if(gnuRet == 0) {
- /* we got a handshake, now print session info */
- print_info(pNsd->sess);
+ /* we got a handshake, now check authorization */
+ // TODO: do it!
}
break;
default:
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 0be5d49a..367a239f 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -223,6 +223,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
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 */
+ RS_RET_TLS_NO_CERT = -2085, /**< no TLS certificate available where one was expected */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */