Commit ee5c9db7 authored by Bastien Durel's avatar Bastien Durel
Browse files

gnutls

parent b6835ce4
......@@ -2,8 +2,8 @@ SRC=main.cpp
OBJ=$(SRC:.cpp=.o)
NAME=cnx
CXXFLAGS=$(shell pkg-config --cflags gio-2.0) -g3 -O0
LDFLAGS=$(shell pkg-config --libs gio-2.0)
CXXFLAGS=$(shell pkg-config --cflags gnutls) -g3 -O0
LDFLAGS=$(shell pkg-config --libs gnutls)
$(NAME): $(OBJ)
$(CXX) -o $(NAME) $(LDFLAGS) $(OBJ)
......
#include <gio/gio.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const GTlsCertificateFlags FLAGS = (GTlsCertificateFlags)
(G_TLS_CERTIFICATE_EXPIRED | G_TLS_CERTIFICATE_REVOKED | G_TLS_CERTIFICATE_BAD_IDENTITY);
#define GTLSERR(msg) { cerr << #msg << gnutls_strerror (r) << endl; return 1; }
#define CHECK(msg) if (r != GNUTLS_E_SUCCESS ) GTLSERR(msg)
#define CHECKNEG(msg) if (r < 0) GTLSERR(msg)
#define CHECKB(fd) if (fd < 0) { perror("socket error"); return 2; }
static int _verify_certificate_callback(gnutls_session_t session);
int main() {
cout << "start" << endl;
GError *err = 0;
gnutls_global_init();
gnutls_session_t sess;
int r = gnutls_init (&sess, GNUTLS_CLIENT );
CHECK(gnutls_init);
const char *pos;
r = gnutls_priority_set_direct (sess, "PFS", &pos);
CHECK(gnutls_priority_set_direct);
gnutls_certificate_credentials_t cred = NULL;
r = gnutls_certificate_allocate_credentials (&cred);
CHECK(gnutls_certificate_allocate_credentials);
static const char ca_bundle[] = "/etc/ssl/certs/ca-certificates.crt";
r = gnutls_certificate_set_x509_trust_file
(cred, ca_bundle, GNUTLS_X509_FMT_PEM);
CHECKNEG(gnutls_certificate_set_x509_trust_file);
gnutls_certificate_set_verify_function(cred, _verify_certificate_callback);
r = gnutls_credentials_set (sess, GNUTLS_CRD_CERTIFICATE, cred);
CHECK(gnutls_credentials_set);
struct addrinfo hints = {0, AF_INET, SOCK_STREAM, IPPROTO_TCP};
struct addrinfo *res = 0;
const char * host = "arrakeen.geekwu.org";
r = getaddrinfo(host, "https", &hints, &res);
if (r != 0) { cerr << gai_strerror(r) << endl; return 3; }
int sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
CHECKB(sock);
int c = connect(sock, res->ai_addr, res->ai_addrlen);
CHECKB(c);
cout << "connected" << endl;
gnutls_transport_set_int (sess, sock);
r = gnutls_server_name_set(sess, GNUTLS_NAME_DNS, host, strlen(host));
CHECK(gnutls_server_name_set);
GSocketClient *client = g_socket_client_new ();
cout << "client: " << client << endl;
r = gnutls_handshake(sess);
CHECK(gnutls_handshake);
g_socket_client_set_tls (client, true);
g_socket_client_set_tls_validation_flags (client, FLAGS);
unsigned certslen = 0;
const gnutls_datum_t *const certs =
gnutls_certificate_get_peers(sess, &certslen);
if (certs == 0 || certslen == 0) {
cerr << "error in gnutls_certificate_get_peers" << endl;
return 4;
}
cout << "got " << certslen << " certs" << endl;
GSocketConnection * cnx = g_socket_client_connect_to_host
(client, "arrakeen.geekwu.org", 443, NULL, &err);
if (err != NULL) {
cerr << "Unable to connect: " << err->message << endl;
gnutls_x509_crt_t cert;
r = gnutls_x509_crt_init (&cert); CHECK(gnutls_x509_crt_init);
r = gnutls_x509_crt_import (cert, certs, GNUTLS_X509_FMT_DER); CHECK(gnutls_x509_crt_import);
r = gnutls_x509_crt_check_hostname(cert, host);
if (r == 0) {
cerr << "error: host name does not match certificate" << endl;
return 5;
}
cout << "cnx: " << cnx << endl;
gnutls_x509_crt_deinit (cert);
return 0;
}
static int _verify_certificate_callback(gnutls_session_t session)
{
unsigned int status;
int ret, type;
const char *hostname;
gnutls_datum_t out;
/* read hostname */
hostname = (char*)gnutls_session_get_ptr(session);
/* This verification function uses the trusted CAs in the credentials
* structure. So you must have installed one or more CA certificates.
*/
ret = gnutls_certificate_verify_peers3(session, hostname, &status);
if (ret < 0) {
printf("Error\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
type = gnutls_certificate_type_get(session);
ret =
gnutls_certificate_verification_status_print
(status, (gnutls_certificate_type_t)type, &out, 0);
if (ret < 0) {
printf("Error\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
cout << out.data << endl;
gnutls_free(out.data);
if (status != 0) /* Certificate is not trusted */
return GNUTLS_E_CERTIFICATE_ERROR;
/* notify gnutls to continue handshake normally */
return 0;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment