comparison libpurple/certificate.c @ 27931:d8e6a2d592a4

propagate from branch 'im.pidgin.pidgin' (head 66190c21dfe7125476caca3c14725bac9db8b71b) to branch 'im.pidgin.pidgin.yaz' (head 30f1655106c7764e3f9cfc8a139784d9b0bd4459)
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Tue, 03 Mar 2009 06:57:02 +0000
parents 93950851db8c 8c8948b9f602
children f058edca3d66
comparison
equal deleted inserted replaced
27930:25319f536d93 27931:d8e6a2d592a4
49 PurpleCertificateVerifiedCallback cb, 49 PurpleCertificateVerifiedCallback cb,
50 gpointer cb_data) 50 gpointer cb_data)
51 { 51 {
52 PurpleCertificateVerificationRequest *vrq; 52 PurpleCertificateVerificationRequest *vrq;
53 PurpleCertificateScheme *scheme; 53 PurpleCertificateScheme *scheme;
54 54
55 g_return_if_fail(subject_name != NULL); 55 g_return_if_fail(subject_name != NULL);
56 /* If you don't have a cert to check, why are you requesting that it 56 /* If you don't have a cert to check, why are you requesting that it
57 be verified? */ 57 be verified? */
58 g_return_if_fail(cert_chain != NULL); 58 g_return_if_fail(cert_chain != NULL);
59 g_return_if_fail(cb != NULL); 59 g_return_if_fail(cb != NULL);
95 } else { 95 } else {
96 purple_debug_info("certificate", 96 purple_debug_info("certificate",
97 "Failed to verify certificate for %s\n", 97 "Failed to verify certificate for %s\n",
98 vrq->subject_name); 98 vrq->subject_name);
99 } 99 }
100 100
101 101
102 102
103 103
104 /* Pass the results on to the request's callback */ 104 /* Pass the results on to the request's callback */
105 (vrq->cb)(st, vrq->cb_data); 105 (vrq->cb)(st, vrq->cb_data);
106 106
107 /* And now to eliminate the request */ 107 /* And now to eliminate the request */
108 /* Fetch the Verifier responsible... */ 108 /* Fetch the Verifier responsible... */
152 152
153 void 153 void
154 purple_certificate_destroy (PurpleCertificate *crt) 154 purple_certificate_destroy (PurpleCertificate *crt)
155 { 155 {
156 PurpleCertificateScheme *scheme; 156 PurpleCertificateScheme *scheme;
157 157
158 if (NULL == crt) return; 158 if (NULL == crt) return;
159 159
160 scheme = crt->scheme; 160 scheme = crt->scheme;
161 161
162 (scheme->destroy_certificate)(crt); 162 (scheme->destroy_certificate)(crt);
204 uid = purple_certificate_get_unique_id((PurpleCertificate *) chain->data); 204 uid = purple_certificate_get_unique_id((PurpleCertificate *) chain->data);
205 purple_debug_info("certificate", 205 purple_debug_info("certificate",
206 "Checking signature chain for uid=%s\n", 206 "Checking signature chain for uid=%s\n",
207 uid); 207 uid);
208 g_free(uid); 208 g_free(uid);
209 209
210 /* If this is a single-certificate chain, say that it is valid */ 210 /* If this is a single-certificate chain, say that it is valid */
211 if (chain->next == NULL) { 211 if (chain->next == NULL) {
212 purple_debug_info("certificate", 212 purple_debug_info("certificate",
213 "...Singleton. We'll say it's valid.\n"); 213 "...Singleton. We'll say it's valid.\n");
214 return TRUE; 214 return TRUE;
216 216
217 /* Load crt with the first certificate */ 217 /* Load crt with the first certificate */
218 crt = (PurpleCertificate *)(chain->data); 218 crt = (PurpleCertificate *)(chain->data);
219 /* And start with the second certificate in the chain */ 219 /* And start with the second certificate in the chain */
220 for ( cur = chain->next; cur; cur = cur->next ) { 220 for ( cur = chain->next; cur; cur = cur->next ) {
221 221
222 issuer = (PurpleCertificate *)(cur->data); 222 issuer = (PurpleCertificate *)(cur->data);
223 223
224 /* Check the signature for this link */ 224 /* Check the signature for this link */
225 if (! purple_certificate_signed_by(crt, issuer) ) { 225 if (! purple_certificate_signed_by(crt, issuer) ) {
226 uid = purple_certificate_get_unique_id(issuer); 226 uid = purple_certificate_get_unique_id(issuer);
227 purple_debug_info("certificate", 227 purple_debug_info("certificate",
228 "...Bad or missing signature by %s\nChain is INVALID\n", 228 "...Bad or missing signature by %s\nChain is INVALID\n",
229 uid); 229 uid);
230 g_free(uid); 230 g_free(uid);
231 231
232 return FALSE; 232 return FALSE;
233 } 233 }
234 234
235 uid = purple_certificate_get_unique_id(issuer); 235 uid = purple_certificate_get_unique_id(issuer);
236 purple_debug_info("certificate", 236 purple_debug_info("certificate",
237 "...Good signature by %s\n", 237 "...Good signature by %s\n",
238 uid); 238 uid);
239 g_free(uid); 239 g_free(uid);
240 240
241 /* The issuer is now the next crt whose signature is to be 241 /* The issuer is now the next crt whose signature is to be
242 checked */ 242 checked */
243 crt = issuer; 243 crt = issuer;
244 } 244 }
245 245
281 281
282 g_return_val_if_fail(crt, NULL); 282 g_return_val_if_fail(crt, NULL);
283 g_return_val_if_fail(crt->scheme, NULL); 283 g_return_val_if_fail(crt->scheme, NULL);
284 284
285 scheme = crt->scheme; 285 scheme = crt->scheme;
286 286
287 g_return_val_if_fail(scheme->get_fingerprint_sha1, NULL); 287 g_return_val_if_fail(scheme->get_fingerprint_sha1, NULL);
288 288
289 fpr = (scheme->get_fingerprint_sha1)(crt); 289 fpr = (scheme->get_fingerprint_sha1)(crt);
290 290
291 return fpr; 291 return fpr;
352 PurpleCertificateScheme *scheme; 352 PurpleCertificateScheme *scheme;
353 353
354 g_return_val_if_fail(crt, FALSE); 354 g_return_val_if_fail(crt, FALSE);
355 355
356 scheme = crt->scheme; 356 scheme = crt->scheme;
357 357
358 g_return_val_if_fail(scheme, FALSE); 358 g_return_val_if_fail(scheme, FALSE);
359 359
360 /* If both provided references are NULL, what are you doing calling 360 /* If both provided references are NULL, what are you doing calling
361 this? */ 361 this? */
362 g_return_val_if_fail( (activation != NULL) || (expiration != NULL), FALSE); 362 g_return_val_if_fail( (activation != NULL) || (expiration != NULL), FALSE);
369 gchar * 369 gchar *
370 purple_certificate_pool_mkpath(PurpleCertificatePool *pool, const gchar *id) 370 purple_certificate_pool_mkpath(PurpleCertificatePool *pool, const gchar *id)
371 { 371 {
372 gchar *path; 372 gchar *path;
373 gchar *esc_scheme_name, *esc_name, *esc_id; 373 gchar *esc_scheme_name, *esc_name, *esc_id;
374 374
375 g_return_val_if_fail(pool, NULL); 375 g_return_val_if_fail(pool, NULL);
376 g_return_val_if_fail(pool->scheme_name, NULL); 376 g_return_val_if_fail(pool->scheme_name, NULL);
377 g_return_val_if_fail(pool->name, NULL); 377 g_return_val_if_fail(pool->name, NULL);
378 378
379 /* Escape all the elements for filesystem-friendliness */ 379 /* Escape all the elements for filesystem-friendliness */
380 esc_scheme_name = pool ? g_strdup(purple_escape_filename(pool->scheme_name)) : NULL; 380 esc_scheme_name = pool ? g_strdup(purple_escape_filename(pool->scheme_name)) : NULL;
381 esc_name = pool ? g_strdup(purple_escape_filename(pool->name)) : NULL; 381 esc_name = pool ? g_strdup(purple_escape_filename(pool->name)) : NULL;
382 esc_id = id ? g_strdup(purple_escape_filename(id)) : NULL; 382 esc_id = id ? g_strdup(purple_escape_filename(id)) : NULL;
383 383
384 path = g_build_filename(purple_user_dir(), 384 path = g_build_filename(purple_user_dir(),
385 "certificates", /* TODO: constantize this? */ 385 "certificates", /* TODO: constantize this? */
386 esc_scheme_name, 386 esc_scheme_name,
387 esc_name, 387 esc_name,
388 esc_id, 388 esc_id,
402 402
403 /* Check that the pool's scheme is loaded */ 403 /* Check that the pool's scheme is loaded */
404 if (purple_certificate_find_scheme(pool->scheme_name) == NULL) { 404 if (purple_certificate_find_scheme(pool->scheme_name) == NULL) {
405 return FALSE; 405 return FALSE;
406 } 406 }
407 407
408 return TRUE; 408 return TRUE;
409 } 409 }
410 410
411 PurpleCertificateScheme * 411 PurpleCertificateScheme *
412 purple_certificate_pool_get_scheme(PurpleCertificatePool *pool) 412 purple_certificate_pool_get_scheme(PurpleCertificatePool *pool)
439 439
440 gboolean 440 gboolean
441 purple_certificate_pool_store(PurpleCertificatePool *pool, const gchar *id, PurpleCertificate *crt) 441 purple_certificate_pool_store(PurpleCertificatePool *pool, const gchar *id, PurpleCertificate *crt)
442 { 442 {
443 gboolean ret = FALSE; 443 gboolean ret = FALSE;
444 444
445 g_return_val_if_fail(pool, FALSE); 445 g_return_val_if_fail(pool, FALSE);
446 g_return_val_if_fail(id, FALSE); 446 g_return_val_if_fail(id, FALSE);
447 g_return_val_if_fail(pool->put_cert, FALSE); 447 g_return_val_if_fail(pool->put_cert, FALSE);
448 448
449 /* Whether crt->scheme matches find_scheme(pool->scheme_name) is not 449 /* Whether crt->scheme matches find_scheme(pool->scheme_name) is not
459 purple_signal_emit(pool, "certificate-stored", 459 purple_signal_emit(pool, "certificate-stored",
460 pool, id); 460 pool, id);
461 } 461 }
462 462
463 return ret; 463 return ret;
464 } 464 }
465 465
466 gboolean 466 gboolean
467 purple_certificate_pool_delete(PurpleCertificatePool *pool, const gchar *id) 467 purple_certificate_pool_delete(PurpleCertificatePool *pool, const gchar *id)
468 { 468 {
469 gboolean ret = FALSE; 469 gboolean ret = FALSE;
470 470
471 g_return_val_if_fail(pool, FALSE); 471 g_return_val_if_fail(pool, FALSE);
472 g_return_val_if_fail(id, FALSE); 472 g_return_val_if_fail(id, FALSE);
473 g_return_val_if_fail(pool->delete_cert, FALSE); 473 g_return_val_if_fail(pool->delete_cert, FALSE);
474 474
475 ret = (pool->delete_cert)(id); 475 ret = (pool->delete_cert)(id);
494 494
495 void 495 void
496 purple_certificate_pool_destroy_idlist(GList *idlist) 496 purple_certificate_pool_destroy_idlist(GList *idlist)
497 { 497 {
498 GList *l; 498 GList *l;
499 499
500 /* Iterate through and free them strings */ 500 /* Iterate through and free them strings */
501 for ( l = idlist; l; l = l->next ) { 501 for ( l = idlist; l; l = l->next ) {
502 g_free(l->data); 502 g_free(l->data);
503 } 503 }
504 504
518 purple_debug_info("certificate/x509_singleuse", 518 purple_debug_info("certificate/x509_singleuse",
519 "VRQ on cert from %s gave %d\n", 519 "VRQ on cert from %s gave %d\n",
520 vrq->subject_name, id); 520 vrq->subject_name, id);
521 521
522 /* Signal what happened back to the caller */ 522 /* Signal what happened back to the caller */
523 if (1 == id) { 523 if (1 == id) {
524 /* Accepted! */ 524 /* Accepted! */
525 purple_certificate_verify_complete(vrq, 525 purple_certificate_verify_complete(vrq,
526 PURPLE_CERTIFICATE_VALID); 526 PURPLE_CERTIFICATE_VALID);
527 } else { 527 } else {
528 /* Not accepted */ 528 /* Not accepted */
555 if (purple_certificate_check_subject_name(crt, vrq->subject_name)) { 555 if (purple_certificate_check_subject_name(crt, vrq->subject_name)) {
556 cn_match = ""; 556 cn_match = "";
557 } else { 557 } else {
558 cn_match = _("(DOES NOT MATCH)"); 558 cn_match = _("(DOES NOT MATCH)");
559 } 559 }
560 560
561 /* Make messages */ 561 /* Make messages */
562 primary = g_strdup_printf(_("%s has presented the following certificate for just-this-once use:"), vrq->subject_name); 562 primary = g_strdup_printf(_("%s has presented the following certificate for just-this-once use:"), vrq->subject_name);
563 secondary = g_strdup_printf(_("Common name: %s %s\nFingerprint (SHA1): %s"), cn, cn_match, sha_asc); 563 secondary = g_strdup_printf(_("Common name: %s %s\nFingerprint (SHA1): %s"), cn, cn_match, sha_asc);
564 564
565 /* Make a semi-pretty display */ 565 /* Make a semi-pretty display */
566 purple_request_accept_cancel( 566 purple_request_accept_cancel(
567 vrq->cb_data, /* TODO: Find what the handle ought to be */ 567 vrq->cb_data, /* TODO: Find what the handle ought to be */
568 _("Single-use Certificate Verification"), 568 _("Single-use Certificate Verification"),
569 primary, 569 primary,
573 NULL, /* No other user */ 573 NULL, /* No other user */
574 NULL, /* No associated conversation */ 574 NULL, /* No associated conversation */
575 vrq, 575 vrq,
576 x509_singleuse_verify_cb, 576 x509_singleuse_verify_cb,
577 x509_singleuse_verify_cb ); 577 x509_singleuse_verify_cb );
578 578
579 /* Cleanup */ 579 /* Cleanup */
580 g_free(primary); 580 g_free(primary);
581 g_free(secondary); 581 g_free(secondary);
582 g_free(sha_asc); 582 g_free(sha_asc);
583 g_byte_array_free(sha_bin, TRUE); 583 g_byte_array_free(sha_bin, TRUE);
642 { 642 {
643 x509_ca_element *el; 643 x509_ca_element *el;
644 644
645 /* lazy_init calls this function, so calling lazy_init here is a 645 /* lazy_init calls this function, so calling lazy_init here is a
646 Bad Thing */ 646 Bad Thing */
647 647
648 g_return_val_if_fail(crt, FALSE); 648 g_return_val_if_fail(crt, FALSE);
649 g_return_val_if_fail(crt->scheme, FALSE); 649 g_return_val_if_fail(crt->scheme, FALSE);
650 /* Make sure that this is some kind of X.509 certificate */ 650 /* Make sure that this is some kind of X.509 certificate */
651 /* TODO: Perhaps just check crt->scheme->name instead? */ 651 /* TODO: Perhaps just check crt->scheme->name instead? */
652 g_return_val_if_fail(crt->scheme == purple_certificate_find_scheme(x509_ca.scheme_name), FALSE); 652 g_return_val_if_fail(crt->scheme == purple_certificate_find_scheme(x509_ca.scheme_name), FALSE);
653 653
654 el = g_new0(x509_ca_element, 1); 654 el = g_new0(x509_ca_element, 1);
655 el->dn = purple_certificate_get_unique_id(crt); 655 el->dn = purple_certificate_get_unique_id(crt);
656 el->crt = purple_certificate_copy(crt); 656 el->crt = purple_certificate_copy(crt);
657 x509_ca_certs = g_list_prepend(x509_ca_certs, el); 657 x509_ca_certs = g_list_prepend(x509_ca_certs, el);
658 658
673 PurpleCertificateScheme *x509; 673 PurpleCertificateScheme *x509;
674 GDir *certdir; 674 GDir *certdir;
675 const gchar *entry; 675 const gchar *entry;
676 GPatternSpec *pempat; 676 GPatternSpec *pempat;
677 GList *iter = NULL; 677 GList *iter = NULL;
678 678
679 if (x509_ca_initialized) return TRUE; 679 if (x509_ca_initialized) return TRUE;
680 680
681 /* Check that X.509 is registered */ 681 /* Check that X.509 is registered */
682 x509 = purple_certificate_find_scheme(x509_ca.scheme_name); 682 x509 = purple_certificate_find_scheme(x509_ca.scheme_name);
683 if ( !x509 ) { 683 if ( !x509 ) {
789 { 789 {
790 GList *cur; 790 GList *cur;
791 791
792 for (cur = lst; cur; cur = cur->next) { 792 for (cur = lst; cur; cur = cur->next) {
793 x509_ca_element *el = cur->data; 793 x509_ca_element *el = cur->data;
794 if (el->dn && !strcmp(dn, el->dn)) { 794 if (purple_strequal(dn, el->dn)) {
795 return el; 795 return el;
796 } 796 }
797 } 797 }
798 return NULL; 798 return NULL;
799 } 799 }
830 to play with */ 830 to play with */
831 crt = purple_certificate_copy(el->crt); 831 crt = purple_certificate_copy(el->crt);
832 } else { 832 } else {
833 crt = NULL; 833 crt = NULL;
834 } 834 }
835 835
836 return crt; 836 return crt;
837 } 837 }
838 838
839 static gboolean 839 static gboolean
840 x509_ca_put_cert(const gchar *id, PurpleCertificate *crt) 840 x509_ca_put_cert(const gchar *id, PurpleCertificate *crt)
841 { 841 {
842 gboolean ret = FALSE; 842 gboolean ret = FALSE;
843 843
844 g_return_val_if_fail(x509_ca_lazy_init(), FALSE); 844 g_return_val_if_fail(x509_ca_lazy_init(), FALSE);
845 845
846 /* TODO: This is a quick way of doing this. At some point the change 846 /* TODO: This is a quick way of doing this. At some point the change
847 ought to be flushed to disk somehow. */ 847 ought to be flushed to disk somehow. */
848 ret = x509_ca_quiet_put_cert(crt); 848 ret = x509_ca_quiet_put_cert(crt);
852 852
853 static gboolean 853 static gboolean
854 x509_ca_delete_cert(const gchar *id) 854 x509_ca_delete_cert(const gchar *id)
855 { 855 {
856 x509_ca_element *el; 856 x509_ca_element *el;
857 857
858 g_return_val_if_fail(x509_ca_lazy_init(), FALSE); 858 g_return_val_if_fail(x509_ca_lazy_init(), FALSE);
859 g_return_val_if_fail(id, FALSE); 859 g_return_val_if_fail(id, FALSE);
860 860
861 /* Is the id even in the pool? */ 861 /* Is the id even in the pool? */
862 el = x509_ca_locate_cert(x509_ca_certs, id); 862 el = x509_ca_locate_cert(x509_ca_certs, id);
868 } 868 }
869 869
870 /* Unlink it from the memory cache and destroy it */ 870 /* Unlink it from the memory cache and destroy it */
871 x509_ca_certs = g_list_remove(x509_ca_certs, el); 871 x509_ca_certs = g_list_remove(x509_ca_certs, el);
872 x509_ca_element_free(el); 872 x509_ca_element_free(el);
873 873
874 return TRUE; 874 return TRUE;
875 } 875 }
876 876
877 static GList * 877 static GList *
878 x509_ca_get_idlist(void) 878 x509_ca_get_idlist(void)
879 { 879 {
880 GList *l, *idlist; 880 GList *l, *idlist;
881 881
882 g_return_val_if_fail(x509_ca_lazy_init(), NULL); 882 g_return_val_if_fail(x509_ca_lazy_init(), NULL);
883 883
884 idlist = NULL; 884 idlist = NULL;
885 for (l = x509_ca_certs; l; l = l->next) { 885 for (l = x509_ca_certs; l; l = l->next) {
886 x509_ca_element *el = l->data; 886 x509_ca_element *el = l->data;
887 idlist = g_list_prepend(idlist, g_strdup(el->dn)); 887 idlist = g_list_prepend(idlist, g_strdup(el->dn));
888 } 888 }
889 889
890 return idlist; 890 return idlist;
891 } 891 }
892 892
893 893
894 static PurpleCertificatePool x509_ca = { 894 static PurpleCertificatePool x509_ca = {
919 static gboolean 919 static gboolean
920 x509_tls_peers_init(void) 920 x509_tls_peers_init(void)
921 { 921 {
922 gchar *poolpath; 922 gchar *poolpath;
923 int ret; 923 int ret;
924 924
925 /* Set up key cache here if it isn't already done */ 925 /* Set up key cache here if it isn't already done */
926 poolpath = purple_certificate_pool_mkpath(&x509_tls_peers, NULL); 926 poolpath = purple_certificate_pool_mkpath(&x509_tls_peers, NULL);
927 ret = purple_build_dir(poolpath, 0700); /* Make it this user only */ 927 ret = purple_build_dir(poolpath, 0700); /* Make it this user only */
928 928
929 g_free(poolpath); 929 g_free(poolpath);
935 static gboolean 935 static gboolean
936 x509_tls_peers_cert_in_pool(const gchar *id) 936 x509_tls_peers_cert_in_pool(const gchar *id)
937 { 937 {
938 gchar *keypath; 938 gchar *keypath;
939 gboolean ret = FALSE; 939 gboolean ret = FALSE;
940 940
941 g_return_val_if_fail(id, FALSE); 941 g_return_val_if_fail(id, FALSE);
942 942
943 keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id); 943 keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);
944 944
945 ret = g_file_test(keypath, G_FILE_TEST_IS_REGULAR); 945 ret = g_file_test(keypath, G_FILE_TEST_IS_REGULAR);
946 946
947 g_free(keypath); 947 g_free(keypath);
948 return ret; 948 return ret;
949 } 949 }
950 950
951 static PurpleCertificate * 951 static PurpleCertificate *
952 x509_tls_peers_get_cert(const gchar *id) 952 x509_tls_peers_get_cert(const gchar *id)
953 { 953 {
954 PurpleCertificateScheme *x509; 954 PurpleCertificateScheme *x509;
955 PurpleCertificate *crt; 955 PurpleCertificate *crt;
956 gchar *keypath; 956 gchar *keypath;
957 957
958 g_return_val_if_fail(id, NULL); 958 g_return_val_if_fail(id, NULL);
959 959
960 /* Is it in the pool? */ 960 /* Is it in the pool? */
961 if ( !x509_tls_peers_cert_in_pool(id) ) { 961 if ( !x509_tls_peers_cert_in_pool(id) ) {
962 return NULL; 962 return NULL;
963 } 963 }
964 964
965 /* Look up the X.509 scheme */ 965 /* Look up the X.509 scheme */
966 x509 = purple_certificate_find_scheme("x509"); 966 x509 = purple_certificate_find_scheme("x509");
967 g_return_val_if_fail(x509, NULL); 967 g_return_val_if_fail(x509, NULL);
968 968
969 /* Okay, now find and load that key */ 969 /* Okay, now find and load that key */
988 g_return_val_if_fail(crt->scheme == purple_certificate_find_scheme(x509_tls_peers.scheme_name), FALSE); 988 g_return_val_if_fail(crt->scheme == purple_certificate_find_scheme(x509_tls_peers.scheme_name), FALSE);
989 989
990 /* Work out the filename and export */ 990 /* Work out the filename and export */
991 keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id); 991 keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);
992 ret = purple_certificate_export(keypath, crt); 992 ret = purple_certificate_export(keypath, crt);
993 993
994 g_free(keypath); 994 g_free(keypath);
995 return ret; 995 return ret;
996 } 996 }
997 997
998 static gboolean 998 static gboolean
1010 id); 1010 id);
1011 return FALSE; 1011 return FALSE;
1012 } 1012 }
1013 1013
1014 /* OK, so work out the keypath and delete the thing */ 1014 /* OK, so work out the keypath and delete the thing */
1015 keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id); 1015 keypath = purple_certificate_pool_mkpath(&x509_tls_peers, id);
1016 if ( unlink(keypath) != 0 ) { 1016 if ( unlink(keypath) != 0 ) {
1017 purple_debug_error("certificate/tls_peers", 1017 purple_debug_error("certificate/tls_peers",
1018 "Unlink of %s failed!\n", 1018 "Unlink of %s failed!\n",
1019 keypath); 1019 keypath);
1020 ret = FALSE; 1020 ret = FALSE;
1045 1045
1046 /* Traverse the directory listing and create an idlist */ 1046 /* Traverse the directory listing and create an idlist */
1047 while ( (entry = g_dir_read_name(dir)) != NULL ) { 1047 while ( (entry = g_dir_read_name(dir)) != NULL ) {
1048 /* Unescape the filename */ 1048 /* Unescape the filename */
1049 const char *unescaped = purple_unescape_filename(entry); 1049 const char *unescaped = purple_unescape_filename(entry);
1050 1050
1051 /* Copy the entry name into our list (GLib owns the original 1051 /* Copy the entry name into our list (GLib owns the original
1052 string) */ 1052 string) */
1053 idlist = g_list_prepend(idlist, g_strdup(unescaped)); 1053 idlist = g_list_prepend(idlist, g_strdup(unescaped));
1054 } 1054 }
1055 1055
1056 /* Release the directory */ 1056 /* Release the directory */
1057 g_dir_close(dir); 1057 g_dir_close(dir);
1058 1058
1059 return idlist; 1059 return idlist;
1060 } 1060 }
1061 1061
1062 static PurpleCertificatePool x509_tls_peers = { 1062 static PurpleCertificatePool x509_tls_peers = {
1063 "x509", /* Scheme name */ 1063 "x509", /* Scheme name */
1141 PurpleCertificateVerificationRequest *vrq; 1141 PurpleCertificateVerificationRequest *vrq;
1142 PurpleCertificatePool *tls_peers; 1142 PurpleCertificatePool *tls_peers;
1143 1143
1144 g_return_if_fail(c); 1144 g_return_if_fail(c);
1145 g_return_if_fail(c->vrq); 1145 g_return_if_fail(c->vrq);
1146 1146
1147 vrq = c->vrq; 1147 vrq = c->vrq;
1148 1148
1149 x509_tls_cached_ua_ctx_free(c); 1149 x509_tls_cached_ua_ctx_free(c);
1150 1150
1151 tls_peers = purple_certificate_find_pool("x509","tls_peers"); 1151 tls_peers = purple_certificate_find_pool("x509","tls_peers");
1153 if (2 == id) { 1153 if (2 == id) {
1154 gchar *cache_id = vrq->subject_name; 1154 gchar *cache_id = vrq->subject_name;
1155 purple_debug_info("certificate/x509/tls_cached", 1155 purple_debug_info("certificate/x509/tls_cached",
1156 "User ACCEPTED cert\nCaching first in chain for future use as %s...\n", 1156 "User ACCEPTED cert\nCaching first in chain for future use as %s...\n",
1157 cache_id); 1157 cache_id);
1158 1158
1159 purple_certificate_pool_store(tls_peers, cache_id, 1159 purple_certificate_pool_store(tls_peers, cache_id,
1160 vrq->cert_chain->data); 1160 vrq->cert_chain->data);
1161 1161
1162 purple_certificate_verify_complete(vrq, 1162 purple_certificate_verify_complete(vrq,
1163 PURPLE_CERTIFICATE_VALID); 1163 PURPLE_CERTIFICATE_VALID);
1193 gchar *primary; 1193 gchar *primary;
1194 1194
1195 /* Make messages */ 1195 /* Make messages */
1196 primary = g_strdup_printf(_("Accept certificate for %s?"), 1196 primary = g_strdup_printf(_("Accept certificate for %s?"),
1197 vrq->subject_name); 1197 vrq->subject_name);
1198 1198
1199 /* Make a semi-pretty display */ 1199 /* Make a semi-pretty display */
1200 purple_request_action( 1200 purple_request_action(
1201 vrq->cb_data, /* TODO: Find what the handle ought to be */ 1201 vrq->cb_data, /* TODO: Find what the handle ought to be */
1202 _("SSL Certificate Verification"), 1202 _("SSL Certificate Verification"),
1203 primary, 1203 primary,
1209 x509_tls_cached_ua_ctx_new(vrq, reason), 1209 x509_tls_cached_ua_ctx_new(vrq, reason),
1210 3, /* Number of actions */ 1210 3, /* Number of actions */
1211 _("Accept"), x509_tls_cached_user_auth_accept_cb, 1211 _("Accept"), x509_tls_cached_user_auth_accept_cb,
1212 _("Reject"), x509_tls_cached_user_auth_reject_cb, 1212 _("Reject"), x509_tls_cached_user_auth_reject_cb,
1213 _("_View Certificate..."), x509_tls_cached_show_cert); 1213 _("_View Certificate..."), x509_tls_cached_show_cert);
1214 1214
1215 /* Cleanup */ 1215 /* Cleanup */
1216 g_free(primary); 1216 g_free(primary);
1217 } 1217 }
1218 1218
1219 static void 1219 static void
1223 1223
1224 purple_debug_info("certificate/x509/tls_cached", 1224 purple_debug_info("certificate/x509/tls_cached",
1225 "Certificate for %s does not match cached. " 1225 "Certificate for %s does not match cached. "
1226 "Auto-rejecting!\n", 1226 "Auto-rejecting!\n",
1227 vrq->subject_name); 1227 vrq->subject_name);
1228 1228
1229 purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID); 1229 purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_INVALID);
1230 return; 1230 return;
1231 } 1231 }
1232 1232
1233 static void 1233 static void
1243 "tls_peers"); 1243 "tls_peers");
1244 1244
1245 /* The peer's certificate should be the first in the list */ 1245 /* The peer's certificate should be the first in the list */
1246 PurpleCertificate *peer_crt = 1246 PurpleCertificate *peer_crt =
1247 (PurpleCertificate *) vrq->cert_chain->data; 1247 (PurpleCertificate *) vrq->cert_chain->data;
1248 1248
1249 PurpleCertificate *cached_crt; 1249 PurpleCertificate *cached_crt;
1250 GByteArray *peer_fpr, *cached_fpr; 1250 GByteArray *peer_fpr, *cached_fpr;
1251 1251
1252 /* Load up the cached certificate */ 1252 /* Load up the cached certificate */
1253 cached_crt = purple_certificate_pool_retrieve( 1253 cached_crt = purple_certificate_pool_retrieve(
1276 purple_debug_info("certificate/x509/tls_cached", 1276 purple_debug_info("certificate/x509/tls_cached",
1277 "Peer cert did NOT match cached\n"); 1277 "Peer cert did NOT match cached\n");
1278 /* vrq now becomes the problem of the user */ 1278 /* vrq now becomes the problem of the user */
1279 x509_tls_cached_unknown_peer(vrq); 1279 x509_tls_cached_unknown_peer(vrq);
1280 } 1280 }
1281 1281
1282 purple_certificate_destroy(cached_crt); 1282 purple_certificate_destroy(cached_crt);
1283 g_byte_array_free(peer_fpr, TRUE); 1283 g_byte_array_free(peer_fpr, TRUE);
1284 g_byte_array_free(cached_fpr, TRUE); 1284 g_byte_array_free(cached_fpr, TRUE);
1285 } 1285 }
1286 1286
1303 1303
1304 /* TODO: Figure out a way to check for a bad signature, as opposed to 1304 /* TODO: Figure out a way to check for a bad signature, as opposed to
1305 "not self-signed" */ 1305 "not self-signed" */
1306 if ( purple_certificate_signed_by(peer_crt, peer_crt) ) { 1306 if ( purple_certificate_signed_by(peer_crt, peer_crt) ) {
1307 gchar *msg; 1307 gchar *msg;
1308 1308
1309 purple_debug_info("certificate/x509/tls_cached", 1309 purple_debug_info("certificate/x509/tls_cached",
1310 "Certificate for %s is self-signed.\n", 1310 "Certificate for %s is self-signed.\n",
1311 vrq->subject_name); 1311 vrq->subject_name);
1312 1312
1313 /* Prompt the user to authenticate the certificate */ 1313 /* Prompt the user to authenticate the certificate */
1314 /* vrq will be completed by user_auth */ 1314 /* vrq will be completed by user_auth */
1315 msg = g_strdup_printf(_("The certificate presented by \"%s\" " 1315 msg = g_strdup_printf(_("The certificate presented by \"%s\" "
1316 "is self-signed. It cannot be " 1316 "is self-signed. It cannot be "
1317 "automatically checked."), 1317 "automatically checked."),
1318 vrq->subject_name); 1318 vrq->subject_name);
1319 1319
1320 x509_tls_cached_user_auth(vrq,msg); 1320 x509_tls_cached_user_auth(vrq,msg);
1321 1321
1322 g_free(msg); 1322 g_free(msg);
1323 return; 1323 return;
1324 } /* if (self signed) */ 1324 } /* if (self signed) */
1325 1325
1326 /* Next, check that the certificate chain is valid */ 1326 /* Next, check that the certificate chain is valid */
1327 if ( ! purple_certificate_check_signature_chain(chain) ) { 1327 if ( ! purple_certificate_check_signature_chain(chain) ) {
1328 /* TODO: Tell the user where the chain broke? */ 1328 /* TODO: Tell the user where the chain broke? */
1329 /* TODO: This error will hopelessly confuse any 1329 /* TODO: This error will hopelessly confuse any
1330 non-elite user. */ 1330 non-elite user. */
1390 "is unknown to Pidgin.")); 1390 "is unknown to Pidgin."));
1391 return; 1391 return;
1392 } 1392 }
1393 1393
1394 g_free(ca_id); 1394 g_free(ca_id);
1395 1395
1396 /* Check the signature */ 1396 /* Check the signature */
1397 if ( !purple_certificate_signed_by(end_crt, ca_crt) ) { 1397 if ( !purple_certificate_signed_by(end_crt, ca_crt) ) {
1398 /* TODO: If signed_by ever returns a reason, maybe mention 1398 /* TODO: If signed_by ever returns a reason, maybe mention
1399 that, too. */ 1399 that, too. */
1400 /* TODO: Also mention the CA involved. While I could do this 1400 /* TODO: Also mention the CA involved. While I could do this
1408 "%s does not have a valid digital " 1408 "%s does not have a valid digital "
1409 "signature from the Certificate " 1409 "signature from the Certificate "
1410 "Authority from which it claims to " 1410 "Authority from which it claims to "
1411 "have a signature."), 1411 "have a signature."),
1412 vrq->subject_name); 1412 vrq->subject_name);
1413 1413
1414 purple_notify_error(NULL, /* TODO: Probably wrong */ 1414 purple_notify_error(NULL, /* TODO: Probably wrong */
1415 _("SSL Certificate Error"), 1415 _("SSL Certificate Error"),
1416 _("Invalid certificate authority" 1416 _("Invalid certificate authority"
1417 " signature"), 1417 " signature"),
1418 secondary); 1418 secondary);
1427 /* Last, check that the hostname matches */ 1427 /* Last, check that the hostname matches */
1428 if ( ! purple_certificate_check_subject_name(peer_crt, 1428 if ( ! purple_certificate_check_subject_name(peer_crt,
1429 vrq->subject_name) ) { 1429 vrq->subject_name) ) {
1430 gchar *sn = purple_certificate_get_subject_name(peer_crt); 1430 gchar *sn = purple_certificate_get_subject_name(peer_crt);
1431 gchar *msg; 1431 gchar *msg;
1432 1432
1433 purple_debug_info("certificate/x509/tls_cached", 1433 purple_debug_info("certificate/x509/tls_cached",
1434 "Name mismatch: Certificate given for %s " 1434 "Name mismatch: Certificate given for %s "
1435 "has a name of %s\n", 1435 "has a name of %s\n",
1436 vrq->subject_name, sn); 1436 vrq->subject_name, sn);
1437 1437
1443 "claims to be from \"%s\" instead. " 1443 "claims to be from \"%s\" instead. "
1444 "This could mean that you are not " 1444 "This could mean that you are not "
1445 "connecting to the service you " 1445 "connecting to the service you "
1446 "believe you are."), 1446 "believe you are."),
1447 vrq->subject_name, sn); 1447 vrq->subject_name, sn);
1448 1448
1449 x509_tls_cached_user_auth(vrq,msg); 1449 x509_tls_cached_user_auth(vrq,msg);
1450 1450
1451 g_free(sn); 1451 g_free(sn);
1452 g_free(msg); 1452 g_free(msg);
1453 return; 1453 return;
1467 } else { 1467 } else {
1468 purple_debug_error("certificate/x509/tls_cached", 1468 purple_debug_error("certificate/x509/tls_cached",
1469 "Unable to locate tls_peers certificate " 1469 "Unable to locate tls_peers certificate "
1470 "cache.\n"); 1470 "cache.\n");
1471 } 1471 }
1472 1472
1473 /* Whew! Done! */ 1473 /* Whew! Done! */
1474 purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID); 1474 purple_certificate_verify_complete(vrq, PURPLE_CERTIFICATE_VALID);
1475 } 1475 }
1476 1476
1477 static void 1477 static void
1483 g_return_if_fail(vrq); 1483 g_return_if_fail(vrq);
1484 1484
1485 purple_debug_info("certificate/x509/tls_cached", 1485 purple_debug_info("certificate/x509/tls_cached",
1486 "Starting verify for %s\n", 1486 "Starting verify for %s\n",
1487 vrq->subject_name); 1487 vrq->subject_name);
1488 1488
1489 tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,tls_peers_name); 1489 tls_peers = purple_certificate_find_pool(x509_tls_cached.scheme_name,tls_peers_name);
1490 1490
1491 if (!tls_peers) { 1491 if (!tls_peers) {
1492 purple_debug_error("certificate/x509/tls_cached", 1492 purple_debug_error("certificate/x509/tls_cached",
1493 "Couldn't find local peers cache %s\n", 1493 "Couldn't find local peers cache %s\n",
1496 1496
1497 /* vrq now becomes the problem of unknown_peer */ 1497 /* vrq now becomes the problem of unknown_peer */
1498 x509_tls_cached_unknown_peer(vrq); 1498 x509_tls_cached_unknown_peer(vrq);
1499 return; 1499 return;
1500 } 1500 }
1501 1501
1502 /* Check if the peer has a certificate cached already */ 1502 /* Check if the peer has a certificate cached already */
1503 purple_debug_info("certificate/x509/tls_cached", 1503 purple_debug_info("certificate/x509/tls_cached",
1504 "Checking for cached cert...\n"); 1504 "Checking for cached cert...\n");
1505 if (purple_certificate_pool_contains(tls_peers, vrq->subject_name)) { 1505 if (purple_certificate_pool_contains(tls_peers, vrq->subject_name)) {
1506 purple_debug_info("certificate/x509/tls_cached", 1506 purple_debug_info("certificate/x509/tls_cached",
1585 purple_debug_warning("certificate", 1585 purple_debug_warning("certificate",
1586 "CertificateScheme %s requested but not found.\n", 1586 "CertificateScheme %s requested but not found.\n",
1587 name); 1587 name);
1588 1588
1589 /* TODO: Signalling and such? */ 1589 /* TODO: Signalling and such? */
1590 1590
1591 return NULL; 1591 return NULL;
1592 } 1592 }
1593 1593
1594 GList * 1594 GList *
1595 purple_certificate_get_schemes(void) 1595 purple_certificate_get_schemes(void)
1613 /* TODO: Signalling and such? */ 1613 /* TODO: Signalling and such? */
1614 1614
1615 purple_debug_info("certificate", 1615 purple_debug_info("certificate",
1616 "CertificateScheme %s registered\n", 1616 "CertificateScheme %s registered\n",
1617 scheme->name); 1617 scheme->name);
1618 1618
1619 return TRUE; 1619 return TRUE;
1620 } 1620 }
1621 1621
1622 gboolean 1622 gboolean
1623 purple_certificate_unregister_scheme(PurpleCertificateScheme *scheme) 1623 purple_certificate_unregister_scheme(PurpleCertificateScheme *scheme)
1666 purple_debug_warning("certificate", 1666 purple_debug_warning("certificate",
1667 "CertificateVerifier %s, %s requested but not found.\n", 1667 "CertificateVerifier %s, %s requested but not found.\n",
1668 scheme_name, ver_name); 1668 scheme_name, ver_name);
1669 1669
1670 /* TODO: Signalling and such? */ 1670 /* TODO: Signalling and such? */
1671 1671
1672 return NULL; 1672 return NULL;
1673 } 1673 }
1674 1674
1675 1675
1676 GList * 1676 GList *
1744 purple_debug_warning("certificate", 1744 purple_debug_warning("certificate",
1745 "CertificatePool %s, %s requested but not found.\n", 1745 "CertificatePool %s, %s requested but not found.\n",
1746 scheme_name, pool_name); 1746 scheme_name, pool_name);
1747 1747
1748 /* TODO: Signalling and such? */ 1748 /* TODO: Signalling and such? */
1749 1749
1750 return NULL; 1750 return NULL;
1751 1751
1752 } 1752 }
1753 1753
1754 GList * 1754 GList *
1832 if (pool->uninit) { 1832 if (pool->uninit) {
1833 pool->uninit(); 1833 pool->uninit();
1834 } 1834 }
1835 1835
1836 cert_pools = g_list_remove(cert_pools, pool); 1836 cert_pools = g_list_remove(cert_pools, pool);
1837 1837
1838 /* TODO: Signalling? */ 1838 /* TODO: Signalling? */
1839 purple_signal_unregister(pool, "certificate-stored"); 1839 purple_signal_unregister(pool, "certificate-stored");
1840 purple_signal_unregister(pool, "certificate-deleted"); 1840 purple_signal_unregister(pool, "certificate-deleted");
1841 1841
1842 purple_debug_info("certificate", 1842 purple_debug_info("certificate",
1843 "CertificatePool %s unregistered\n", 1843 "CertificatePool %s unregistered\n",
1844 pool->name); 1844 pool->name);
1845 return TRUE; 1845 return TRUE;
1846 } 1846 }