| 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; |