diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/examples/Makefile.am | 2 | ||||
-rw-r--r-- | doc/manpages/certtool.1 | 2 | ||||
-rw-r--r-- | doc/tex/ex-cert-select.tex | 205 | ||||
-rw-r--r-- | doc/tex/examples.tex | 5 |
4 files changed, 204 insertions, 10 deletions
diff --git a/doc/examples/Makefile.am b/doc/examples/Makefile.am index 9b365b0f9f..d8e6e4b297 100644 --- a/doc/examples/Makefile.am +++ b/doc/examples/Makefile.am @@ -1,4 +1,4 @@ -EXTRA_DIST = ex-alert.c ex-client-resume.c ex-client-srp.c ex-client1.c \ +EXTRA_DIST = ex-alert.c ex-client-resume.c ex-client-srp.c \ ex-client2.c ex-x509-info.c ex-rfc2818.c ex-serv-export.c ex-serv-pgp.c \ ex-serv-srp.c ex-serv1.c ex-pgp-keyserver.c ex-cert-select.c \ ex-crq.c ex-session-info.c ex-pkcs12.c diff --git a/doc/manpages/certtool.1 b/doc/manpages/certtool.1 index 35a9de17ed..8921256683 100644 --- a/doc/manpages/certtool.1 +++ b/doc/manpages/certtool.1 @@ -55,6 +55,8 @@ Update a signed certificate. .SS Controlling output .IP "\-8, \-\-pkcs8" Use PKCS #8 format for private keys. +.IP "\-\-dsa" +Generate a DSA key. .IP "\-\-bits BITS" Specify the number of bits for key generation. .IP "\-\-export\-ciphers" diff --git a/doc/tex/ex-cert-select.tex b/doc/tex/ex-cert-select.tex index 796f2e568f..2137bebb92 100644 --- a/doc/tex/ex-cert-select.tex +++ b/doc/tex/ex-cert-select.tex @@ -2,21 +2,202 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> #include <gnutls/gnutls.h> #include <gnutls/x509.h> +/* A TLS client that loads the certificate and key. + */ + +#define MAX_BUF 1024 +#define SA struct sockaddr +#define MSG "GET / HTTP/1.0\r\n\r\n" + +#define CERT_FILE "cert.pem" +#define KEY_FILE "key.pem" +#define CAFILE "ca.pem" + +static int cert_callback(gnutls_session session, + const gnutls_datum* req_ca_rdn, int nreqs, + gnutls_retr_st * st); + +gnutls_x509_crt crt; +gnutls_x509_privkey key; + +/* Helper functions to load a certificate and key + * files into memory. They use mmap for simplicity. + */ +static gnutls_datum mmap_file( const char* file) +{ +int fd; +gnutls_datum mmaped_file = { NULL, 0 }; +struct stat stat_st; +void* ptr; + + fd = open( file, 0); + if (fd==-1) return mmaped_file; + + fstat( fd, &stat_st); + + if ((ptr=mmap( NULL, stat_st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) + return mmaped_file; + + mmaped_file.data = ptr; + mmaped_file.size = stat_st.st_size; + + return mmaped_file; +} + +static void munmap_file( gnutls_datum data) +{ + munmap( data.data, data.size); +} + +/* Load the certificate and the private key. + */ +static void load_keys( void) +{ +int ret; +gnutls_datum data; + + data = mmap_file( CERT_FILE); + if (data.data == NULL) { + fprintf(stderr, "*** Error loading cert file.\n"); + exit(1); + } + gnutls_x509_crt_init( &crt); + + ret = gnutls_x509_crt_import( crt, &data, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "*** Error loading key file: %s\n", gnutls_strerror(ret)); + exit(1); + } + + munmap_file( data); + + data = mmap_file( KEY_FILE); + if (data.data == NULL) { + fprintf(stderr, "*** Error loading key file.\n"); + exit(1); + } + + gnutls_x509_privkey_init( &key); + + ret = gnutls_x509_privkey_import( key, &data, GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "*** Error loading key file: %s\n", gnutls_strerror(ret)); + exit(1); + } + + munmap_file( data); + +} + +int main() +{ + int ret, sd, ii; + gnutls_session session; + char buffer[MAX_BUF + 1]; + gnutls_certificate_credentials xcred; + /* Allow connections to servers that have OpenPGP keys as well. + */ + + gnutls_global_init(); + + load_keys(); + + /* 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_client_set_retrieve_function( xcred, cert_callback); + + /* Initialize TLS session + */ + gnutls_init(&session, GNUTLS_CLIENT); + + /* Use default priorities */ + gnutls_set_default_priority(session); + + /* 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)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_global_deinit(); + + return 0; +} + + + /* This callback should be associated with a session by calling - * gnutls_certificate_client_set_select_function( session, cert_callback), + * gnutls_certificate_client_set_retrieve_function( session, cert_callback), * before a handshake. */ static int cert_callback(gnutls_session session, - const gnutls_datum * client_certs, int client_certs_num, - const gnutls_datum * req_ca_rdn, int nreqs) + const gnutls_datum* req_ca_rdn, int nreqs, + gnutls_retr_st * st) { char issuer_dn[256]; int i, ret; size_t len; + gnutls_certificate_type type; /* Print the server's trusted CAs */ @@ -35,11 +216,23 @@ static int cert_callback(gnutls_session session, } } - /* Select a certificate from the client_certs and return its - * index. + /* Select a certificate and return it. */ - return -1; + type = gnutls_certificate_type_get( session); + if (type == GNUTLS_CRT_X509) { + st->type = type; + st->ncerts = 1; + + st->cert.x509 = &crt; + st->key.x509 = key; + + st->deinit_all = 0; + } else { + return -1; + } + + return 0; } diff --git a/doc/tex/examples.tex b/doc/tex/examples.tex index 31a38c972d..544b502616 100644 --- a/doc/tex/examples.tex +++ b/doc/tex/examples.tex @@ -37,9 +37,8 @@ Real world programs should be able to handle certificate chains as well. \subsection{Using a callback to select the certificate to use} There are cases where a client holds several certificate and key pairs, -and may want to choose the appropriate to send in the current session. -The following example demonstrates the use of the certificate selection callback -to assist in this purpose. +and may not want to load all of them in the credentials structure. +The following example demonstrates the use of the certificate selection callback. \par \input{ex-cert-select} |