From d594f83a893a517328f55b0b0b3240c4073efb89 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 8 May 2008 16:00:57 +0200 Subject: server's X509 cert fingerprint is obtained by client on connect --- runtime/nsd_gtls.c | 234 +++++++++++------------------------------------------ 1 file changed, 47 insertions(+), 187 deletions(-) (limited to 'runtime/nsd_gtls.c') 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; } -- cgit