Mercurial > pidgin
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 |