Mercurial > pidgin.yaz
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 } |