+
+
+#if HAVE_GNUTLS_H
+/* gnutls_x509_crt_print appeared in 1.7.6. Memory leaks were fixed in 1.7.9.
+ GNUTLS_CRT_PRINT_FULL appeared in 2.4.0. */
+#if GNUTLS_VERSION_NUMBER >= 0x020400
+#define USE_GNUTLS_X509_CRT_PRINT 1
+#else
+#define USE_GNUTLS_X509_CRT_PRINT 0
+#endif
+
+
+#if USE_GNUTLS_X509_CRT_PRINT
+#else
+static const char *bin2hex(const void *bin, size_t bin_size)
+{
+ static char printable[110];
+ const unsigned char *_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, "%.2x ", _bin[i]);
+ print += 2;
+ }
+ return printable;
+}
+
+static void x509_crt_print(gnutls_x509_crt_t cert)
+{
+ time_t expiration_time, activation_time;
+ size_t size;
+ char serial[40];
+ char dn[256];
+ unsigned int algo, bits;
+
+ expiration_time = gnutls_x509_crt_get_expiration_time(cert);
+ activation_time = gnutls_x509_crt_get_activation_time(cert);
+
+ printf("\tCertificate is valid since: %s", ctime(&activation_time));
+ printf("\tCertificate expires: %s", ctime(&expiration_time));
+
+ /* Print the serial number of the certificate. */
+ size = sizeof(serial);
+ gnutls_x509_crt_get_serial(cert, serial, &size);
+
+ printf("\tCertificate serial number: %s\n", bin2hex(serial, size));
+
+ /* Extract some of the public key algorithm's parameters
+ */
+ algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
+
+ printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
+
+ /* Print the version of the X.509 certificate. */
+ printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
+
+ size = sizeof(dn);
+ gnutls_x509_crt_get_dn(cert, dn, &size);
+ printf("\tDN: %s\n", dn);
+
+ size = sizeof(dn);
+ gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
+ printf("\tIssuer's DN: %s\n", dn);
+}
+#endif
+#endif
+
+void cs_print_session_info(COMSTACK cs)
+{
+#if HAVE_GNUTLS_H
+ struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
+ if (cs->type == ssl_type && sp->session)
+ {
+ const gnutls_datum_t *cert_list;
+ unsigned i, cert_list_size;
+ if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
+ return;
+ printf("X509 certificate\n");
+ cert_list = gnutls_certificate_get_peers(sp->session,
+ &cert_list_size);
+ printf("Peer provided %u certificates\n", cert_list_size);
+ for (i = 0; i < cert_list_size; i++)
+ {
+ gnutls_x509_crt_t cert;
+#if USE_GNUTLS_X509_CRT_PRINT
+ int ret;
+ gnutls_datum_t cinfo;
+#endif
+ gnutls_x509_crt_init(&cert);
+ gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
+ printf("Certificate info %d:\n", i + 1);
+#if USE_GNUTLS_X509_CRT_PRINT
+ ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
+ &cinfo);
+ if (ret == 0)
+ {
+ printf("\t%s\n", cinfo.data);
+ gnutls_free(cinfo.data);
+ }
+#else
+ x509_crt_print(cert);
+#endif
+ gnutls_x509_crt_deinit(cert);
+
+ }
+ }
+#elif HAVE_OPENSSL_SSL_H
+ if (cs->type == ssl_type)
+ {
+ struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
+ SSL *ssl = (SSL *) sp->ssl;
+ if (ssl)
+ {
+ X509 *server_cert = SSL_get_peer_certificate(ssl);
+ if (server_cert)
+ {
+ char *pem_buf;
+ int pem_len;
+ BIO *bio = BIO_new(BIO_s_mem());
+
+ /* get PEM buffer in memory */
+ PEM_write_bio_X509(bio, server_cert);
+ pem_len = BIO_get_mem_data(bio, &pem_buf);
+ fwrite(pem_buf, pem_len, 1, stdout);
+
+ /* print all info on screen .. */
+ X509_print_fp(stdout, server_cert);
+ BIO_free(bio);
+
+ X509_free(server_cert);
+ }
+ }
+ }
+#endif
+}
+
+void *cs_get_ssl(COMSTACK cs)
+{
+#if HAVE_OPENSSL_SSL_H
+ if (cs && cs->type == ssl_type)
+ {
+ struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
+ return sp->ssl;
+ }
+#endif
+ return 0;
+}
+
+int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
+{
+#if ENABLE_SSL
+ if (cs && cs->type == ssl_type)
+ {
+#if HAVE_OPENSSL_SSL_H
+ struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
+ if (sp->ctx_alloc)
+ return 0;
+ sp->ctx = (SSL_CTX *) ctx;
+#endif
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
+{
+#if ENABLE_SSL
+ if (cs && cs->type == ssl_type)
+ {
+ struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
+ strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
+ sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
+{
+#if HAVE_OPENSSL_SSL_H
+ SSL *ssl = (SSL *) cs_get_ssl(cs);
+ if (ssl)
+ {
+ X509 *server_cert = SSL_get_peer_certificate(ssl);
+ if (server_cert)
+ {
+ BIO *bio = BIO_new(BIO_s_mem());
+ char *pem_buf;
+ /* get PEM buffer in memory */
+ PEM_write_bio_X509(bio, server_cert);
+ *len = BIO_get_mem_data(bio, &pem_buf);
+ *buf = (char *) xmalloc(*len);
+ memcpy(*buf, pem_buf, *len);
+ BIO_free(bio);
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+static int tcpip_put_connect(COMSTACK h, char *buf, int size)
+{
+ struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+
+ int r = tcpip_put(h, state->connect_request_buf,
+ state->connect_request_len);
+ if (r == 0)
+ {
+ /* it's sent */
+ h->f_put = tcpip_put; /* switch to normal tcpip put */
+ r = tcpip_put(h, buf, size);
+ }
+ return r;
+}
+
+static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize)
+{
+ struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+ int r;
+
+ r = tcpip_get(h, &state->connect_response_buf,
+ &state->connect_response_len);
+ if (r < 1)
+ return r;
+ /* got the connect response completely */
+ state->complete = cs_complete_auto; /* switch to normal tcpip get */
+ h->f_get = tcpip_get;
+ return tcpip_get(h, buf, bufsize);
+}
+
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+