comparison libpurple/plugins/ssl/ssl-gnutls.c @ 17793:deb00aacc93c

merge of '03ea20ce538dad585a5a2d40778f242a1fd85a4b' and '04e67ab53da79e8268e027ed9b4423c64c6b86ee'
author William Ehlhardt <williamehlhardt@gmail.com>
date Thu, 31 May 2007 00:40:46 +0000
parents 393cf111f366 3ce170204ef0
children 91feef6cbede
comparison
equal deleted inserted replaced
17792:393cf111f366 17793:deb00aacc93c
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */ 21 */
22 #include "internal.h" 22 #include "internal.h"
23 #include "debug.h" 23 #include "debug.h"
24 #include "plugin.h" 24 #include "plugin.h"
25 #include "request.h"
26 #include "sslconn.h" 25 #include "sslconn.h"
27 #include "version.h" 26 #include "version.h"
28 #include "util.h" 27 #include "util.h"
29 28
30 #define SSL_GNUTLS_PLUGIN_ID "ssl-gnutls" 29 #define SSL_GNUTLS_PLUGIN_ID "ssl-gnutls"
48 ssl_gnutls_init_gnutls(void) 47 ssl_gnutls_init_gnutls(void)
49 { 48 {
50 gnutls_global_init(); 49 gnutls_global_init();
51 50
52 gnutls_certificate_allocate_credentials(&xcred); 51 gnutls_certificate_allocate_credentials(&xcred);
53 /*gnutls_certificate_set_x509_trust_file(xcred, "ca.pem", 52 gnutls_certificate_set_x509_trust_file(xcred, "ca.pem",
54 GNUTLS_X509_FMT_PEM);*/ 53 GNUTLS_X509_FMT_PEM);
55 } 54 }
56 55
57 static gboolean 56 static gboolean
58 ssl_gnutls_init(void) 57 ssl_gnutls_init(void)
59 { 58 {
66 gnutls_global_deinit(); 65 gnutls_global_deinit();
67 66
68 gnutls_certificate_free_credentials(xcred); 67 gnutls_certificate_free_credentials(xcred);
69 } 68 }
70 69
71 /** Callback from the dialog in ssl_gnutls_authcheck_ask */
72 static void ssl_gnutls_authcheck_cb(PurpleSslConnection * gsc, gint choice)
73 {
74 if (NULL == gsc)
75 {
76 purple_debug_error("gnutls","Inappropriate NULL argument at %s:%d\n",
77 __FILE__, (int) __LINE__);
78 return;
79 }
80
81 switch(choice)
82 {
83 case 1: /* "Accept" */
84 /* TODO: Shoud PURPLE_INPUT_READ be hardcoded? */
85 gsc->connect_cb(gsc->connect_cb_data, gsc, PURPLE_INPUT_READ);
86 break;
87
88 default: /* "Cancel" or otherwise...? */
89 purple_debug_info("gnutls",
90 "User rejected certificate from %s\n",
91 gsc->host);
92 if(gsc->error_cb != NULL)
93 gsc->error_cb(gsc, PURPLE_SSL_PEER_AUTH_FAILED,
94 gsc->connect_cb_data);
95 purple_ssl_close(gsc);
96 }
97 }
98
99 /** Pop up a dialog asking for verification of the given certificate */
100 static void ssl_gnutls_authcheck_ask(PurpleSslConnection * gsc)
101 {
102 PurpleSslGnutlsData *gnutls_data = PURPLE_SSL_GNUTLS_DATA(gsc);
103
104 const gnutls_datum_t *cert_list;
105 unsigned int cert_list_size = 0;
106 gnutls_session_t session=gnutls_data->session;
107
108 cert_list =
109 gnutls_certificate_get_peers(session, &cert_list_size);
110
111 if (0 == cert_list_size || NULL == cert_list)
112 {
113 /* Peer provided no certificates at all.
114 TODO: We should write a witty message here.
115 */
116 gchar * primary = g_strdup_printf
117 (
118 _("Peer %s provided no certificates.\n Connect anyway?"),
119 gsc->host
120 );
121
122 purple_request_accept_cancel
123 (gsc,
124 _("SSL Authorization Request"),
125 primary,
126 _("The server you are connecting to presented no certificates identifying itself. You have no assurance that you are not connecting to an imposter. Connect anyway?"),
127 2, /* Default action is "Cancel" */
128 NULL, NULL, /* There is no way to extract account data from
129 a connection handle, it seems. */
130 NULL, /* Same goes for the conversation data */
131 gsc, /* Pass connection ptr to callback */
132 ssl_gnutls_authcheck_cb, /* Accept */
133 ssl_gnutls_authcheck_cb /* Cancel */
134 );
135 g_free(primary);
136 }
137 else
138 {
139 /* Grab the first certificate and display some data about it */
140 gchar fpr_bin[256]; /* Raw binary key fingerprint */
141 gsize fpr_bin_sz = sizeof(fpr_bin); /* Size of above (used later) */
142 gchar * fpr_asc = NULL; /* ASCII representation of key fingerprint */
143 gchar ser_bin[256]; /* Certificate Serial Number field */
144 gsize ser_bin_sz = sizeof(ser_bin);
145 gchar * ser_asc = NULL;
146 gchar dn[1024]; /* Certificate Name field */
147 gsize dn_sz = sizeof(dn);
148 /* TODO: Analyze certificate time/date stuff */
149 gboolean CERT_OK = TRUE; /* Is the certificate "good"? */
150
151 gnutls_x509_crt_t cert; /* Certificate data itself */
152
153 /* Suck the certificate data into the structure */
154 gnutls_x509_crt_init(&cert);
155 gnutls_x509_crt_import (cert, &cert_list[0],
156 GNUTLS_X509_FMT_DER);
157
158 /* Read key fingerprint */
159 gnutls_x509_crt_get_fingerprint(cert, GNUTLS_MAC_SHA,
160 fpr_bin, &fpr_bin_sz);
161 fpr_asc = purple_base16_encode_chunked(fpr_bin,fpr_bin_sz);
162
163 /* Read serial number */
164 gnutls_x509_crt_get_serial(cert, ser_bin, &ser_bin_sz);
165 ser_asc = purple_base16_encode_chunked(ser_bin,ser_bin_sz);
166
167 /* Read the certificate DN field */
168 gnutls_x509_crt_get_dn(cert, dn, &dn_sz);
169
170 /* TODO: Certificate checking here */
171
172
173 /* Build the dialog */
174 {
175 gchar * primary = NULL;
176 gchar * secondary = NULL;
177
178 if ( CERT_OK == TRUE )
179 {
180 primary = g_strdup_printf
181 (
182 _("Certificate from %s is valid. Accept?"),
183 gsc->host
184 );
185 }
186 else
187 {
188 primary = g_strdup_printf
189 (
190 _("Certificate from %s not valid! Accept anyway?"),
191 gsc->host
192 );
193 }
194
195 secondary = g_strdup_printf
196 (
197 _("Certificate name: %s\nKey fingerprint (SHA1):%s\nSerial Number:%s\nTODO: Expiration dates, etc.\n"),
198 dn, fpr_asc, ser_asc
199 );
200
201 purple_request_accept_cancel
202 (gsc,
203 _("SSL Authorization Request"),
204 primary,
205 secondary,
206 (CERT_OK == TRUE ? 1:2), /* Default action depends on certificate
207 status. */
208 NULL, NULL, /* There is no way to extract account data from
209 a connection handle, it seems. */
210 NULL, /* Same goes for the conversation data */
211 gsc, /* Pass connection ptr to callback */
212 ssl_gnutls_authcheck_cb, /* Accept */
213 ssl_gnutls_authcheck_cb /* Cancel */
214 );
215
216 g_free(primary);
217 g_free(secondary);
218 }
219
220
221 /* Cleanup! */
222 g_free(fpr_asc);
223 g_free(ser_asc);
224
225 gnutls_x509_crt_deinit(cert);
226 }
227 }
228 70
229 static void ssl_gnutls_handshake_cb(gpointer data, gint source, 71 static void ssl_gnutls_handshake_cb(gpointer data, gint source,
230 PurpleInputCondition cond) 72 PurpleInputCondition cond)
231 { 73 {
232 PurpleSslConnection *gsc = data; 74 PurpleSslConnection *gsc = data;
252 94
253 purple_ssl_close(gsc); 95 purple_ssl_close(gsc);
254 } else { 96 } else {
255 purple_debug_info("gnutls", "Handshake complete\n"); 97 purple_debug_info("gnutls", "Handshake complete\n");
256 98
257 /* Spit some key info to debug */
258 { 99 {
259 const gnutls_datum_t *cert_list; 100 const gnutls_datum_t *cert_list;
260 unsigned int cert_list_size = 0; 101 unsigned int cert_list_size = 0;
261 gnutls_session_t session=gnutls_data->session; 102 gnutls_session_t session=gnutls_data->session;
262 103
290 purple_debug_info("gnutls", 131 purple_debug_info("gnutls",
291 "Lvl %d SHA1 fingerprint: %s\n", 132 "Lvl %d SHA1 fingerprint: %s\n",
292 i, fpr_asc); 133 i, fpr_asc);
293 134
294 tsz=sizeof(tbuf); 135 tsz=sizeof(tbuf);
295 int ret = gnutls_x509_crt_get_serial(cert,tbuf,&tsz); 136 gnutls_x509_crt_get_serial(cert,tbuf,&tsz);
296 tasc= 137 tasc=
297 purple_base16_encode_chunked(tbuf, tsz); 138 purple_base16_encode_chunked(tbuf, tsz);
298 purple_debug_info("gnutls", 139 purple_debug_info("gnutls",
299 "Serial: %s(%d bytes, ret=%d)\n", 140 "Serial: %s\n",
300 tasc, tsz, ret); 141 tasc);
301 g_free(tasc); 142 g_free(tasc);
302 143
303 tsz=sizeof(tbuf); 144 tsz=sizeof(tbuf);
304 gnutls_x509_crt_get_dn (cert, tbuf, &tsz); 145 gnutls_x509_crt_get_dn (cert, tbuf, &tsz);
305 purple_debug_info("gnutls", 146 purple_debug_info("gnutls",
309 gnutls_x509_crt_get_issuer_dn (cert, tbuf, &tsz); 150 gnutls_x509_crt_get_issuer_dn (cert, tbuf, &tsz);
310 purple_debug_info("gnutls", 151 purple_debug_info("gnutls",
311 "Cert Issuer DN: %s\n", 152 "Cert Issuer DN: %s\n",
312 tbuf); 153 tbuf);
313 154
314 tsz=sizeof(tbuf);
315 gnutls_x509_crt_get_key_id(cert,0, tbuf, &tsz);
316 tasc = purple_base16_encode_chunked(tbuf, tsz);
317 purple_debug_info("gnutls",
318 "Key ID: %s\n",
319 tasc);
320 g_free(tasc);
321
322 g_free(fpr_asc); fpr_asc = NULL; 155 g_free(fpr_asc); fpr_asc = NULL;
323 gnutls_x509_crt_deinit(cert); 156 gnutls_x509_crt_deinit(cert);
324 } /* for */ 157 }
325 158
326 } /* End keydata spitting */ 159 }
327 160 gsc->connect_cb(gsc->connect_cb_data, gsc, cond);
328 /* Ask for cert verification */
329 } 161 }
330 162
331 } 163 }
332 164
333 165