| [ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
8.1.2 Simple client example with X.509 certificate support
Let’s assume now that we want to create a TCP client which communicates with servers that use X.509 or OpenPGP certificate authentication. The following client is a very simple TLS client, which uses the high level verification functions for certificates, but does not support session resumption.
/* This example code is placed in the public domain. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include "examples.h"
/* A very basic TLS client, with X.509 authentication and server certificate
* verification. Note that error checking for missing files etc. is missing
* for simplicity.
*/
#define MAX_BUF 1024
#define CAFILE "/etc/ssl/certs/ca-certificates.crt"
#define MSG "GET / HTTP/1.0\r\n\r\n"
extern int tcp_connect (void);
extern void tcp_close (int sd);
static int _verify_certificate_callback (gnutls_session_t session);
int main (void)
{
int ret, sd, ii;
gnutls_session_t session;
char buffer[MAX_BUF + 1];
const char *err;
gnutls_certificate_credentials_t xcred;
gnutls_global_init ();
/* X509 stuff */
gnutls_certificate_allocate_credentials (&xcred);
/* sets the trusted cas file
*/
gnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM);
gnutls_certificate_set_verify_function (xcred, _verify_certificate_callback);
/* If client holds a certificate it can be set using the following:
*
gnutls_certificate_set_x509_key_file (xcred,
"cert.pem", "key.pem",
GNUTLS_X509_FMT_PEM);
*/
/* Initialize TLS session
*/
gnutls_init (&session, GNUTLS_CLIENT);
gnutls_session_set_ptr (session, (void *) "my_host_name");
gnutls_server_name_set (session, GNUTLS_NAME_DNS, "my_host_name",
strlen("my_host_name"));
/* Use default priorities */
ret = gnutls_priority_set_direct (session, "NORMAL", &err);
if (ret < 0)
{
if (ret == GNUTLS_E_INVALID_REQUEST)
{
fprintf (stderr, "Syntax error at: %s\n", err);
}
exit (1);
}
/* put the x509 credentials to the current session
*/
gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
/* connect to the peer
*/
sd = tcp_connect ();
gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
/* Perform the TLS handshake
*/
do
{
ret = gnutls_handshake (session);
}
while (ret < 0 && gnutls_error_is_fatal (ret) == 0);
if (ret < 0)
{
fprintf (stderr, "*** Handshake failed\n");
gnutls_perror (ret);
goto end;
}
else
{
printf ("- Handshake was completed\n");
}
gnutls_record_send (session, MSG, strlen (MSG));
ret = gnutls_record_recv (session, buffer, MAX_BUF);
if (ret == 0)
{
printf ("- Peer has closed the TLS connection\n");
goto end;
}
else if (ret < 0)
{
fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret));
goto end;
}
printf ("- Received %d bytes: ", ret);
for (ii = 0; ii < ret; ii++)
{
fputc (buffer[ii], stdout);
}
fputs ("\n", stdout);
gnutls_bye (session, GNUTLS_SHUT_RDWR);
end:
tcp_close (sd);
gnutls_deinit (session);
gnutls_certificate_free_credentials (xcred);
gnutls_global_deinit ();
return 0;
}
/* This function will verify the peer's certificate, and check
* if the hostname matches, as well as the activation, expiration dates.
*/
static int
_verify_certificate_callback (gnutls_session_t session)
{
unsigned int status;
const gnutls_datum_t *cert_list;
unsigned int cert_list_size;
int ret;
gnutls_x509_crt_t cert;
const char *hostname;
/* read hostname */
hostname = 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_peers2 (session, &status);
if (ret < 0)
{
printf ("Error\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (status & GNUTLS_CERT_INVALID)
printf ("The certificate is not trusted.\n");
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
printf ("The certificate hasn't got a known issuer.\n");
if (status & GNUTLS_CERT_REVOKED)
printf ("The certificate has been revoked.\n");
if (status & GNUTLS_CERT_EXPIRED)
printf ("The certificate has expired\n");
if (status & GNUTLS_CERT_NOT_ACTIVATED)
printf ("The certificate is not yet activated\n");
/* Up to here the process is the same for X.509 certificates and
* OpenPGP keys. From now on X.509 certificates are assumed. This can
* be easily extended to work with openpgp keys as well.
*/
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
return GNUTLS_E_CERTIFICATE_ERROR;
if (gnutls_x509_crt_init (&cert) < 0)
{
printf ("error in initialization\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
if (cert_list == NULL)
{
printf ("No certificate was found!\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
/* This is not a real world example, since we only check the first
* certificate in the given chain.
*/
if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
{
printf ("error parsing certificate\n");
return GNUTLS_E_CERTIFICATE_ERROR;
}
if (!gnutls_x509_crt_check_hostname (cert, hostname))
{
printf ("The certificate's owner does not match hostname '%s'\n",
hostname);
return GNUTLS_E_CERTIFICATE_ERROR;
}
gnutls_x509_crt_deinit (cert);
/* notify gnutls to continue handshake normally */
return 0;
}
| [ << ] | [ < ] | [ Up ] | [ > ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated on March 23, 2012 using texi2html 5.0.
