1 /* This example code is placed in the public domain. */
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
16 #include <gnutls/gnutls.h>
17 #include <gnutls/x509.h>
18 #include <gnutls/pkcs11.h>
19 #include <sys/types.h>
23 /* A TLS client that loads the certificate and key.
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.
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
);
65 fprintf (stderr
, "*** Error loading key file: %s\n",
66 gnutls_strerror (ret
));
70 gnutls_pkcs11_privkey_init (&key
);
72 ret
= gnutls_pkcs11_privkey_import_url (key
, KEY_URL
, 0);
75 fprintf (stderr
, "*** Error loading key file: %s\n",
76 gnutls_strerror (ret
));
83 pin_callback (void *user
, int attempt
, const char *token_url
,
84 const char *token_label
, unsigned int flags
, char *pin
,
90 printf ("PIN required for token '%s' with URL '%s'\n", token_label
,
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");
104 len
= MIN (pin_max
, strlen (password
));
105 memcpy (pin
, password
, len
);
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
);
131 gnutls_certificate_allocate_credentials (&xcred
);
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
158 gnutls_transport_set_ptr (session
, (gnutls_transport_ptr_t
) sd
);
160 /* Perform the TLS handshake
162 ret
= gnutls_handshake (session
);
166 fprintf (stderr
, "*** Handshake failed\n");
172 printf ("- Handshake was completed\n");
175 gnutls_record_send (session
, MSG
, strlen (MSG
));
177 ret
= gnutls_record_recv (session
, buffer
, MAX_BUF
);
180 printf ("- Peer has closed the TLS connection\n");
185 fprintf (stderr
, "*** Error: %s\n", gnutls_strerror (ret
));
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
);
202 gnutls_deinit (session
);
204 gnutls_certificate_free_credentials (xcred
);
205 gnutls_priority_deinit (priorities_cache
);
207 gnutls_global_deinit ();
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.
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
)
228 gnutls_certificate_type_t type
;
230 /* Print the server's trusted CAs
233 printf ("- Server's trusted authorities:\n");
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
);
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
;
262 ret
= gnutls_x509_crt_get_signature_algorithm (crt
);
265 /* error reading signature algorithm
274 ret
= gnutls_sign_algorithm_get_requested (session
, i
, &req_algo
);
275 if (ret
>= 0 && cert_algo
== req_algo
)
281 /* server has not requested anything specific */
282 if (i
== 0 && ret
== GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
)
294 ("- Could not find a suitable certificate to send to server\n");
298 st
->cert_type
= type
;
301 st
->cert
.x509
= &crt
;
302 st
->key
.pkcs11
= key
;
303 st
->key_type
= GNUTLS_PRIVKEY_PKCS11
;