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