comparison libpurple/certificate.c @ 19330:b65a23799dc2

In tls_cached: - Replace the "here be certificate info" dialog with one that displays a more friendly message explaining why the user is being bothered. - Unfortunately, the magical voodoo required to make the request API do this right is insufficiently powerful, so a crash happens if you click "View"
author William Ehlhardt <williamehlhardt@gmail.com>
date Sat, 18 Aug 2007 07:21:33 +0000
parents e93db0c87b26
children 920984752314
comparison
equal deleted inserted replaced
19329:e93db0c87b26 19330:b65a23799dc2
1035 1035
1036 1036
1037 /***** A Verifier that uses the tls_peers cache and the CA pool to validate certificates *****/ 1037 /***** A Verifier that uses the tls_peers cache and the CA pool to validate certificates *****/
1038 static PurpleCertificateVerifier x509_tls_cached; 1038 static PurpleCertificateVerifier x509_tls_cached;
1039 1039
1040
1041 /* The following is several hacks piled together and needs to be fixed.
1042 * It exists because show_cert (see its comments) needs the original reason
1043 * given to user_auth in order to rebuild the dialog.
1044 */
1045 /* TODO: This will cause a ua_ctx to become memleaked if the request(s) get
1046 closed by handle or otherwise abnormally. */
1047 typedef struct {
1048 PurpleCertificateVerificationRequest *vrq;
1049 gchar *reason;
1050 } x509_tls_cached_ua_ctx;
1051
1052 static x509_tls_cached_ua_ctx *
1053 x509_tls_cached_ua_ctx_new(PurpleCertificateVerificationRequest *vrq,
1054 const gchar *reason)
1055 {
1056 x509_tls_cached_ua_ctx *c;
1057
1058 c = g_new0(x509_tls_cached_ua_ctx, 1);
1059 c->vrq = vrq;
1060 c->reason = g_strdup(reason);
1061
1062 return c;
1063 }
1064
1065
1040 static void 1066 static void
1041 x509_tls_cached_user_auth_cb (PurpleCertificateVerificationRequest *vrq, gint id) 1067 x509_tls_cached_ua_ctx_free(x509_tls_cached_ua_ctx *c)
1042 { 1068 {
1069 g_return_if_fail(c);
1070 g_free(c->reason);
1071 g_free(c);
1072 }
1073
1074 static void
1075 x509_tls_cached_user_auth(PurpleCertificateVerificationRequest *vrq,
1076 const gchar *reason);
1077
1078 static void
1079 x509_tls_cached_show_cert(x509_tls_cached_ua_ctx *c, gint id)
1080 {
1081 PurpleCertificate *disp_crt = c->vrq->cert_chain->data;
1082 purple_certificate_display_x509(disp_crt);
1083
1084 /* Since clicking a button closes the request, show it again */
1085 x509_tls_cached_user_auth(c->vrq, c->reason);
1086
1087 x509_tls_cached_ua_ctx_free(c);
1088 }
1089
1090 static void
1091 x509_tls_cached_user_auth_cb (x509_tls_cached_ua_ctx *c, gint id)
1092 {
1093 PurpleCertificateVerificationRequest *vrq;
1043 PurpleCertificatePool *tls_peers; 1094 PurpleCertificatePool *tls_peers;
1044 1095
1045 g_return_if_fail(vrq); 1096 g_return_if_fail(c);
1097 g_return_if_fail(c->vrq);
1098
1099 vrq = c->vrq;
1100
1101 x509_tls_cached_ua_ctx_free(c);
1046 1102
1047 tls_peers = purple_certificate_find_pool("x509","tls_peers"); 1103 tls_peers = purple_certificate_find_pool("x509","tls_peers");
1048 1104
1049 if (1 == id) { 1105 if (1 == id) {
1050 gchar *cache_id = vrq->subject_name; 1106 gchar *cache_id = vrq->subject_name;
1063 purple_certificate_verify_complete(vrq, 1119 purple_certificate_verify_complete(vrq,
1064 PURPLE_CERTIFICATE_INVALID); 1120 PURPLE_CERTIFICATE_INVALID);
1065 } 1121 }
1066 } 1122 }
1067 1123
1068 /* Validates a certificate by asking the user */ 1124 /** Validates a certificate by asking the user
1125 * @param reason String to explain why the user needs to accept/refuse the
1126 * certificate.
1127 * @todo Needs a handle argument
1128 */
1069 static void 1129 static void
1070 x509_tls_cached_user_auth(PurpleCertificateVerificationRequest *vrq) 1130 x509_tls_cached_user_auth(PurpleCertificateVerificationRequest *vrq,
1071 { 1131 const gchar *reason)
1072 gchar *sha_asc; 1132 {
1073 GByteArray *sha_bin; 1133 gchar *primary;
1074 gchar *cn; 1134
1075 const gchar *cn_match;
1076 time_t activation, expiration;
1077 /* Length of these buffers is dictated by 'man ctime_r' */
1078 gchar activ_str[26], expir_str[26];
1079 gchar *primary, *secondary;
1080 PurpleCertificate *crt = (PurpleCertificate *) vrq->cert_chain->data;
1081
1082 /* Pull out the SHA1 checksum */
1083 sha_bin = purple_certificate_get_fingerprint_sha1(crt);
1084 /* Now decode it for display */
1085 sha_asc = purple_base16_encode_chunked(sha_bin->data,
1086 sha_bin->len);
1087
1088 /* Get the cert Common Name */
1089 cn = purple_certificate_get_subject_name(crt);
1090
1091 /* Determine whether the name matches */
1092 if (purple_certificate_check_subject_name(crt, vrq->subject_name)) {
1093 cn_match = _("");
1094 } else {
1095 cn_match = _("(DOES NOT MATCH)");
1096 }
1097
1098 /* Get the certificate times */
1099 /* TODO: Check the times against localtime */
1100 /* TODO: errorcheck? */
1101 g_assert(purple_certificate_get_times(crt, &activation, &expiration));
1102 ctime_r(&activation, activ_str);
1103 ctime_r(&expiration, expir_str);
1104
1105 /* Make messages */ 1135 /* Make messages */
1106 primary = g_strdup_printf(_("%s has presented the following certificate:"), vrq->subject_name); 1136 primary = g_strdup_printf(_("Accept certificate for %s?"),
1107 secondary = g_strdup_printf(_("Common name: %s %s\n\nFingerprint (SHA1): %s\n\nActivation date: %s\nExpiration date: %s\n"), cn, cn_match, sha_asc, activ_str, expir_str); 1137 vrq->subject_name);
1108 1138
1109 /* Make a semi-pretty display */ 1139 /* Make a semi-pretty display */
1110 purple_request_accept_cancel( 1140 purple_request_action(
1111 vrq->cb_data, /* TODO: Find what the handle ought to be */ 1141 vrq->cb_data, /* TODO: Find what the handle ought to be */
1112 _("SSL Certificate Verification"), 1142 _("SSL Certificate Verification"),
1113 primary, 1143 primary,
1114 secondary, 1144 reason,
1115 1, /* Accept by default */ 1145 1, /* Accept by default */
1116 NULL, /* No account */ 1146 NULL, /* No account */
1117 NULL, /* No other user */ 1147 NULL, /* No other user */
1118 NULL, /* No associated conversation */ 1148 NULL, /* No associated conversation */
1119 vrq, 1149 x509_tls_cached_ua_ctx_new(vrq, reason),
1120 x509_tls_cached_user_auth_cb, 1150 3, /* Number of actions */
1121 x509_tls_cached_user_auth_cb ); 1151 _("Yes"), x509_tls_cached_user_auth_cb,
1152 _("No"), x509_tls_cached_user_auth_cb,
1153 _("_View Certificate..."), x509_tls_cached_show_cert);
1122 1154
1123 /* Cleanup */ 1155 /* Cleanup */
1124 g_free(primary); 1156 g_free(primary);
1125 g_free(secondary);
1126 g_free(sha_asc);
1127 g_byte_array_free(sha_bin, TRUE);
1128 } 1157 }
1129 1158
1130 static void 1159 static void
1131 x509_tls_cached_peer_cert_changed(PurpleCertificateVerificationRequest *vrq) 1160 x509_tls_cached_peer_cert_changed(PurpleCertificateVerificationRequest *vrq)
1132 { 1161 {
1198 1227
1199 /* First, check that the hostname matches */ 1228 /* First, check that the hostname matches */
1200 if ( ! purple_certificate_check_subject_name(peer_crt, 1229 if ( ! purple_certificate_check_subject_name(peer_crt,
1201 vrq->subject_name) ) { 1230 vrq->subject_name) ) {
1202 gchar *sn = purple_certificate_get_subject_name(peer_crt); 1231 gchar *sn = purple_certificate_get_subject_name(peer_crt);
1232 gchar *msg;
1203 1233
1204 purple_debug_info("certificate/x509/tls_cached", 1234 purple_debug_info("certificate/x509/tls_cached",
1205 "Name mismatch: Certificate given for %s " 1235 "Name mismatch: Certificate given for %s "
1206 "has a name of %s\n", 1236 "has a name of %s\n",
1207 vrq->subject_name, sn); 1237 vrq->subject_name, sn);
1208 g_free(sn);
1209 1238
1210 /* Prompt the user to authenticate the certificate */ 1239 /* Prompt the user to authenticate the certificate */
1211 /* TODO: Provide the user with more guidance about why he is 1240 /* TODO: Provide the user with more guidance about why he is
1212 being prompted */ 1241 being prompted */
1213 /* vrq will be completed by user_auth */ 1242 /* vrq will be completed by user_auth */
1214 x509_tls_cached_user_auth(vrq); 1243 msg = g_strdup_printf(_("The certificate given by %s has a "
1244 "name on it of %s instead. This could "
1245 "mean that you are not connecting to "
1246 "the service you want to."),
1247 vrq->subject_name, sn);
1248
1249 x509_tls_cached_user_auth(vrq,msg);
1250
1251 g_free(sn);
1252 g_free(msg);
1215 return; 1253 return;
1216 } /* if (name mismatch) */ 1254 } /* if (name mismatch) */
1217 1255
1218 1256
1219 1257
1249 loaded, we will simply present it to the user for checking. */ 1287 loaded, we will simply present it to the user for checking. */
1250 if ( !ca ) { 1288 if ( !ca ) {
1251 purple_debug_error("certificate/x509/tls_cached", 1289 purple_debug_error("certificate/x509/tls_cached",
1252 "No X.509 Certificate Authority pool " 1290 "No X.509 Certificate Authority pool "
1253 "could be found!\n"); 1291 "could be found!\n");
1254 1292
1255 /* vrq will be completed by user_auth */ 1293 /* vrq will be completed by user_auth */
1256 x509_tls_cached_user_auth(vrq); 1294 x509_tls_cached_user_auth(vrq,_("You have no database of root "
1295 "certificates, so this "
1296 "certificate cannot be "
1297 "validated."));
1257 return; 1298 return;
1258 } 1299 }
1259 1300
1260 /* TODO: I don't have the Glib documentation handy; is this correct? */ 1301 /* TODO: I don't have the Glib documentation handy; is this correct? */
1261 last = g_list_last(chain); 1302 last = g_list_last(chain);
1271 "Certificate Authority with DN='%s' not " 1312 "Certificate Authority with DN='%s' not "
1272 "found. I'll prompt the user, I guess.\n", 1313 "found. I'll prompt the user, I guess.\n",
1273 ca_id); 1314 ca_id);
1274 g_free(ca_id); 1315 g_free(ca_id);
1275 /* vrq will be completed by user_auth */ 1316 /* vrq will be completed by user_auth */
1276 x509_tls_cached_user_auth(vrq); 1317 x509_tls_cached_user_auth(vrq,_("The root certificate this "
1318 "one claims to be issued by "
1319 "is unknown to Pidgin."));
1277 return; 1320 return;
1278 } 1321 }
1279 1322
1280 ca_crt = purple_certificate_pool_retrieve(ca, ca_id); 1323 ca_crt = purple_certificate_pool_retrieve(ca, ca_id);
1281 g_free(ca_id); 1324 g_free(ca_id);
1751 g_assert(purple_certificate_get_times(crt, &activation, &expiration)); 1794 g_assert(purple_certificate_get_times(crt, &activation, &expiration));
1752 ctime_r(&activation, activ_str); 1795 ctime_r(&activation, activ_str);
1753 ctime_r(&expiration, expir_str); 1796 ctime_r(&expiration, expir_str);
1754 1797
1755 /* Make messages */ 1798 /* Make messages */
1756 title = g_strdup_printf(_("Certificate: %s"), cn); 1799 title = _("Certificate Information");
1757 primary = NULL; 1800 primary = ""; /* libpurple doesn't like NULL messages */
1758 secondary = g_strdup_printf(_("Common name: %s\n\n" 1801 secondary = g_strdup_printf(_("Common name: %s\n\n"
1759 "Fingerprint (SHA1): %s\n\n" 1802 "Fingerprint (SHA1): %s\n\n"
1760 "Activation date: %s\n" 1803 "Activation date: %s\n"
1761 "Expiration date: %s\n"), 1804 "Expiration date: %s\n"),
1762 cn, sha_asc, activ_str, expir_str); 1805 cn, sha_asc, activ_str, expir_str);