documented fixes.
[gnutls.git] / doc / examples / ex-cert-select-pkcs11.c
blob0bd032bf423d7c74a38d1803ef99aba55a6b1bf5
1 /* This example code is placed in the public domain. */
3 #ifdef HAVE_CONFIG_H
4 #include <config.h>
5 #endif
7 #include <getpass.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <unistd.h>
16 #include <gnutls/gnutls.h>
17 #include <gnutls/x509.h>
18 #include <gnutls/pkcs11.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
23 /* A TLS client that loads the certificate and key.
26 #define MAX_BUF 1024
27 #define MSG "GET / HTTP/1.0\r\n\r\n"
28 #define MIN(x,y) (((x)<(y))?(x):(y))
30 #define CAFILE "ca.pem"
31 #define KEY_URL "pkcs11:manufacturer=SomeManufacturer;object=Private%20Key" \
32 ";objecttype=private;id=db:5b:3e:b5:72:33"
33 #define CERT_URL "pkcs11:manufacturer=SomeManufacturer;object=Certificate;" \
34 "objecttype=cert;id=db:5b:3e:b5:72:33"
36 extern int tcp_connect (void);
37 extern void tcp_close (int sd);
39 static int cert_callback (gnutls_session_t session,
40 const gnutls_datum_t * req_ca_rdn, int nreqs,
41 const gnutls_pk_algorithm_t * sign_algos,
42 int sign_algos_length, gnutls_retr2_st * st);
44 gnutls_x509_crt_t crt;
45 gnutls_pkcs11_privkey_t key;
47 /* Load the certificate and the private key.
49 static void
50 load_keys (void)
52 int ret;
54 gnutls_x509_crt_init (&crt);
56 ret = gnutls_x509_crt_import_pkcs11_url (crt, CERT_URL, 0);
58 /* some tokens require login to read data */
59 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
60 ret = gnutls_x509_crt_import_pkcs11_url (crt, CERT_URL,
61 GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
63 if (ret < 0)
65 fprintf (stderr, "*** Error loading key file: %s\n",
66 gnutls_strerror (ret));
67 exit (1);
70 gnutls_pkcs11_privkey_init (&key);
72 ret = gnutls_pkcs11_privkey_import_url (key, KEY_URL, 0);
73 if (ret < 0)
75 fprintf (stderr, "*** Error loading key file: %s\n",
76 gnutls_strerror (ret));
77 exit (1);
82 static int
83 pin_callback (void *user, int attempt, const char *token_url,
84 const char *token_label, unsigned int flags, char *pin,
85 size_t pin_max)
87 const char *password;
88 int len;
90 printf ("PIN required for token '%s' with URL '%s'\n", token_label,
91 token_url);
92 if (flags & GNUTLS_PKCS11_PIN_FINAL_TRY)
93 printf ("*** This is the final try before locking!\n");
94 if (flags & GNUTLS_PKCS11_PIN_COUNT_LOW)
95 printf ("*** Only few tries left before locking!\n");
97 password = getpass ("Enter pin: ");
98 if (password == NULL || password[0] == 0)
100 fprintf (stderr, "No password given\n");
101 exit (1);
104 len = MIN (pin_max, strlen (password));
105 memcpy (pin, password, len);
106 pin[len] = 0;
108 return 0;
112 main (void)
114 int ret, sd, ii;
115 gnutls_session_t session;
116 gnutls_priority_t priorities_cache;
117 char buffer[MAX_BUF + 1];
118 gnutls_certificate_credentials_t xcred;
119 /* Allow connections to servers that have OpenPGP keys as well.
122 gnutls_global_init ();
123 /* PKCS11 private key operations might require PIN.
124 * Register a callback.
126 gnutls_pkcs11_set_pin_function (pin_callback, NULL);
128 load_keys ();
130 /* X509 stuff */
131 gnutls_certificate_allocate_credentials (&xcred);
133 /* priorities */
134 gnutls_priority_init (&priorities_cache, "NORMAL", NULL);
137 /* sets the trusted cas file
139 gnutls_certificate_set_x509_trust_file (xcred, CAFILE, GNUTLS_X509_FMT_PEM);
141 gnutls_certificate_set_retrieve_function (xcred, cert_callback);
143 /* Initialize TLS session
145 gnutls_init (&session, GNUTLS_CLIENT);
147 /* Use default priorities */
148 gnutls_priority_set (session, priorities_cache);
150 /* put the x509 credentials to the current session
152 gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred);
154 /* connect to the peer
156 sd = tcp_connect ();
158 gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd);
160 /* Perform the TLS handshake
162 ret = gnutls_handshake (session);
164 if (ret < 0)
166 fprintf (stderr, "*** Handshake failed\n");
167 gnutls_perror (ret);
168 goto end;
170 else
172 printf ("- Handshake was completed\n");
175 gnutls_record_send (session, MSG, strlen (MSG));
177 ret = gnutls_record_recv (session, buffer, MAX_BUF);
178 if (ret == 0)
180 printf ("- Peer has closed the TLS connection\n");
181 goto end;
183 else if (ret < 0)
185 fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret));
186 goto end;
189 printf ("- Received %d bytes: ", ret);
190 for (ii = 0; ii < ret; ii++)
192 fputc (buffer[ii], stdout);
194 fputs ("\n", stdout);
196 gnutls_bye (session, GNUTLS_SHUT_RDWR);
198 end:
200 tcp_close (sd);
202 gnutls_deinit (session);
204 gnutls_certificate_free_credentials (xcred);
205 gnutls_priority_deinit (priorities_cache);
207 gnutls_global_deinit ();
209 return 0;
214 /* This callback should be associated with a session by calling
215 * gnutls_certificate_client_set_retrieve_function( session, cert_callback),
216 * before a handshake.
219 static int
220 cert_callback (gnutls_session_t session,
221 const gnutls_datum_t * req_ca_rdn, int nreqs,
222 const gnutls_pk_algorithm_t * sign_algos,
223 int sign_algos_length, gnutls_retr2_st * st)
225 char issuer_dn[256];
226 int i, ret;
227 size_t len;
228 gnutls_certificate_type_t type;
230 /* Print the server's trusted CAs
232 if (nreqs > 0)
233 printf ("- Server's trusted authorities:\n");
234 else
235 printf ("- Server did not send us any trusted authorities names.\n");
237 /* print the names (if any) */
238 for (i = 0; i < nreqs; i++)
240 len = sizeof (issuer_dn);
241 ret = gnutls_x509_rdn_get (&req_ca_rdn[i], issuer_dn, &len);
242 if (ret >= 0)
244 printf (" [%d]: ", i);
245 printf ("%s\n", issuer_dn);
249 /* Select a certificate and return it.
250 * The certificate must be of any of the "sign algorithms"
251 * supported by the server.
254 type = gnutls_certificate_type_get (session);
255 if (type == GNUTLS_CRT_X509)
257 /* check if the certificate we are sending is signed
258 * with an algorithm that the server accepts */
259 gnutls_sign_algorithm_t cert_algo, req_algo;
260 int i, match = 0;
262 ret = gnutls_x509_crt_get_signature_algorithm (crt);
263 if (ret < 0)
265 /* error reading signature algorithm
267 return -1;
269 cert_algo = ret;
271 i = 0;
274 ret = gnutls_sign_algorithm_get_requested (session, i, &req_algo);
275 if (ret >= 0 && cert_algo == req_algo)
277 match = 1;
278 break;
281 /* server has not requested anything specific */
282 if (i == 0 && ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
284 match = 1;
285 break;
287 i++;
289 while (ret >= 0);
291 if (match == 0)
293 printf
294 ("- Could not find a suitable certificate to send to server\n");
295 return -1;
298 st->cert_type = type;
299 st->ncerts = 1;
301 st->cert.x509 = &crt;
302 st->key.pkcs11 = key;
303 st->key_type = GNUTLS_PRIVKEY_PKCS11;
305 st->deinit_all = 0;
307 else
309 return -1;
312 return 0;