From b25fd9c6d454492cfa2903fe9261372ceec4b17d Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sun, 16 May 2010 12:06:33 +0200 Subject: Added initial example. --- doc/examples/Makefile.am | 2 +- doc/examples/ex-cert-select-pkcs11.c | 270 +++++++++++++++++++++++++++++++++++ doc/gnutls.texi | 8 ++ 3 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 doc/examples/ex-cert-select-pkcs11.c (limited to 'doc') diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 81548ca7c9..0c055b138b 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -78,4 +78,4 @@ noinst_LTLIBRARIES = libexamples.la libexamples_la_SOURCES = examples.h ex-alert.c ex-pkcs12.c \ ex-rfc2818.c ex-session-info.c ex-x509-info.c ex-verify.c \ - tcp.c + tcp.c ex-cert-select-pkcs11.c diff --git a/doc/examples/ex-cert-select-pkcs11.c b/doc/examples/ex-cert-select-pkcs11.c new file mode 100644 index 0000000000..2538ed0b23 --- /dev/null +++ b/doc/examples/ex-cert-select-pkcs11.c @@ -0,0 +1,270 @@ +/* This example code is placed in the public domain. */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* A TLS client that loads the certificate and key. + */ + +#define MAX_BUF 1024 +#define MSG "GET / HTTP/1.0\r\n\r\n" + +#define CAFILE "ca.pem" +#define CERT_URL "pkcs11:manufacturer=EnterSafe;object=Certificate;id=db:5b:3e:b5:72:33:92:99:18:ed:bb:eb:74:68:31:bd:b2:23:67:26" +#define KEY_URL "pkcs11:manufacturer=EnterSafe;object=Certificate;id=db:5b:3e:b5:72:33:92:99:18:ed:bb:eb:74:68:31:bd:b2:23:67:26" + +extern int tcp_connect (void); +extern void tcp_close (int sd); + +static int cert_callback (gnutls_session_t session, + const gnutls_datum_t * req_ca_rdn, int nreqs, + const gnutls_pk_algorithm_t * sign_algos, + int sign_algos_length, gnutls_retr2_st * st); + +gnutls_x509_crt_t crt; +gnutls_pkcs11_privkey_t key; + +/* Load the certificate and the private key. + */ +static void +load_keys (void) +{ + int ret; + + gnutls_x509_crt_init (&crt); + + ret = gnutls_x509_crt_import_pkcs11_url (crt, CERT_URL); + if (ret < 0) + { + fprintf (stderr, "*** Error loading key file: %s\n", + gnutls_strerror (ret)); + exit (1); + } + + gnutls_pkcs11_privkey_init (&key); + + ret = gnutls_pkcs11_privkey_import_url (key, KEY_URL); + if (ret < 0) + { + fprintf (stderr, "*** Error loading key file: %s\n", + gnutls_strerror (ret)); + exit (1); + } + +} + +int +main (void) +{ + int ret, sd, ii; + gnutls_session_t session; + gnutls_priority_t priorities_cache; + char buffer[MAX_BUF + 1]; + gnutls_certificate_credentials_t xcred; + /* Allow connections to servers that have OpenPGP keys as well. + */ + + gnutls_global_init (); + + load_keys (); + + /* X509 stuff */ + gnutls_certificate_allocate_credentials (&xcred); + + /* priorities */ + gnutls_priority_init (&priorities_cache, "NORMAL", NULL); + + + /* sets the trusted cas file + */ + gnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM); + + gnutls_certificate_set_retrieve_function (xcred, cert_callback); + + /* Initialize TLS session + */ + gnutls_init (&session, GNUTLS_CLIENT); + + /* Use default priorities */ + gnutls_priority_set (session, priorities_cache); + + /* 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 + */ + ret = gnutls_handshake (session); + + 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_priority_deinit (priorities_cache); + + gnutls_global_deinit (); + + return 0; +} + + + +/* This callback should be associated with a session by calling + * gnutls_certificate_client_set_retrieve_function( session, cert_callback), + * before a handshake. + */ + +static int +cert_callback (gnutls_session_t session, + const gnutls_datum_t * req_ca_rdn, int nreqs, + const gnutls_pk_algorithm_t * sign_algos, + int sign_algos_length, gnutls_retr2_st * st) +{ + char issuer_dn[256]; + int i, ret; + size_t len; + gnutls_certificate_type_t type; + + /* Print the server's trusted CAs + */ + if (nreqs > 0) + printf ("- Server's trusted authorities:\n"); + else + printf ("- Server did not send us any trusted authorities names.\n"); + + /* print the names (if any) */ + for (i = 0; i < nreqs; i++) + { + len = sizeof (issuer_dn); + ret = gnutls_x509_rdn_get (&req_ca_rdn[i], issuer_dn, &len); + if (ret >= 0) + { + printf (" [%d]: ", i); + printf ("%s\n", issuer_dn); + } + } + + /* Select a certificate and return it. + * The certificate must be of any of the "sign algorithms" + * supported by the server. + */ + + type = gnutls_certificate_type_get (session); + if (type == GNUTLS_CRT_X509) + { + /* check if the certificate we are sending is signed + * with an algorithm that the server accepts */ + gnutls_sign_algorithm_t cert_algo, req_algo; + int i, match = 0; + + ret = gnutls_x509_crt_get_signature_algorithm (crt); + if (ret < 0) + { + /* error reading signature algorithm + */ + return -1; + } + cert_algo = ret; + + i = 0; + do + { + ret = gnutls_sign_algorithm_get_requested (session, i, &req_algo); + if (ret >= 0 && cert_algo == req_algo) + { + match = 1; + break; + } + + /* server has not requested anything specific */ + if (i == 0 && ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) + { + match = 1; + break; + } + i++; + } + while (ret >= 0); + + if (match == 0) + { + printf + ("- Could not find a suitable certificate to send to server\n"); + return -1; + } + + st->cert_type = type; + st->ncerts = 1; + + st->cert.x509 = &crt; + st->key.pkcs11 = key; + st->key_type = GNUTLS_PRIVKEY_PKCS11; + + st->deinit_all = 0; + } + else + { + return -1; + } + + return 0; + +} diff --git a/doc/gnutls.texi b/doc/gnutls.texi index 7e4c3ca1a2..84cc674447 100644 --- a/doc/gnutls.texi +++ b/doc/gnutls.texi @@ -2617,6 +2617,14 @@ certificate selection callback. @verbatiminclude examples/ex-cert-select.c +@subsection Using a Callback to Select a @acronym{PKCS} #11 Certificate + +This example will demonstrate how to load keys and certificates +from a @acronym{PKCS} #11 module, which is typically used +for keys and certificates stored in smart cards. + +@verbatiminclude examples/ex-cert-select-pkcs11.c + @node Client with Resume capability example @subsection Client with Resume Capability Example @anchor{ex:resume-client} -- cgit v1.2.1