| 32 #include <gnutls/gnutls.h> |
32 #include <gnutls/gnutls.h> |
| 33 #include <gnutls/x509.h> |
33 #include <gnutls/x509.h> |
| 34 |
34 |
| 35 typedef struct |
35 typedef struct |
| 36 { |
36 { |
| 37 gnutls_session session; |
37 gnutls_session_t session; |
| 38 guint handshake_handler; |
38 guint handshake_handler; |
| 39 guint handshake_timer; |
39 guint handshake_timer; |
| 40 } PurpleSslGnutlsData; |
40 } PurpleSslGnutlsData; |
| 41 |
41 |
| 42 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data) |
42 #define PURPLE_SSL_GNUTLS_DATA(gsc) ((PurpleSslGnutlsData *)gsc->private_data) |
| 282 g_byte_array_free(z, TRUE); |
282 g_byte_array_free(z, TRUE); |
| 283 } |
283 } |
| 284 g_list_free(peers); |
284 g_list_free(peers); |
| 285 |
285 |
| 286 { |
286 { |
| 287 const gnutls_datum *cert_list; |
287 const gnutls_datum_t *cert_list; |
| 288 unsigned int cert_list_size = 0; |
288 unsigned int cert_list_size = 0; |
| 289 gnutls_session session=gnutls_data->session; |
289 gnutls_session_t session=gnutls_data->session; |
| 290 int i; |
290 int i; |
| 291 |
291 |
| 292 cert_list = |
292 cert_list = |
| 293 gnutls_certificate_get_peers(session, &cert_list_size); |
293 gnutls_certificate_get_peers(session, &cert_list_size); |
| 294 |
294 |
| 301 gsize fpr_bin_sz = sizeof(fpr_bin); |
301 gsize fpr_bin_sz = sizeof(fpr_bin); |
| 302 gchar * fpr_asc = NULL; |
302 gchar * fpr_asc = NULL; |
| 303 gchar tbuf[256]; |
303 gchar tbuf[256]; |
| 304 gsize tsz=sizeof(tbuf); |
304 gsize tsz=sizeof(tbuf); |
| 305 gchar * tasc = NULL; |
305 gchar * tasc = NULL; |
| 306 gnutls_x509_crt cert; |
306 gnutls_x509_crt_t cert; |
| 307 |
307 |
| 308 gnutls_x509_crt_init(&cert); |
308 gnutls_x509_crt_init(&cert); |
| 309 gnutls_x509_crt_import (cert, &cert_list[i], |
309 gnutls_x509_crt_import (cert, &cert_list[i], |
| 310 GNUTLS_X509_FMT_DER); |
310 GNUTLS_X509_FMT_DER); |
| 311 |
311 |
| 312 gnutls_x509_crt_get_fingerprint(cert, GNUTLS_MAC_SHA, |
312 gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA, |
| 313 fpr_bin, &fpr_bin_sz); |
313 fpr_bin, &fpr_bin_sz); |
| 314 |
314 |
| 315 fpr_asc = |
315 fpr_asc = |
| 316 purple_base16_encode_chunked((const guchar *)fpr_bin, fpr_bin_sz); |
316 purple_base16_encode_chunked((const guchar *)fpr_bin, fpr_bin_sz); |
| 317 |
317 |
| 384 |
384 |
| 385 static void |
385 static void |
| 386 ssl_gnutls_connect(PurpleSslConnection *gsc) |
386 ssl_gnutls_connect(PurpleSslConnection *gsc) |
| 387 { |
387 { |
| 388 PurpleSslGnutlsData *gnutls_data; |
388 PurpleSslGnutlsData *gnutls_data; |
| 389 static const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 }; |
|
| 390 |
389 |
| 391 gnutls_data = g_new0(PurpleSslGnutlsData, 1); |
390 gnutls_data = g_new0(PurpleSslGnutlsData, 1); |
| 392 gsc->private_data = gnutls_data; |
391 gsc->private_data = gnutls_data; |
| 393 |
392 |
| 394 gnutls_init(&gnutls_data->session, GNUTLS_CLIENT); |
393 gnutls_init(&gnutls_data->session, GNUTLS_CLIENT); |
| 410 gnutls_priority_set(gnutls_data->session, default_priority); |
409 gnutls_priority_set(gnutls_data->session, default_priority); |
| 411 } |
410 } |
| 412 #else |
411 #else |
| 413 gnutls_set_default_priority(gnutls_data->session); |
412 gnutls_set_default_priority(gnutls_data->session); |
| 414 #endif |
413 #endif |
| 415 |
|
| 416 gnutls_certificate_type_set_priority(gnutls_data->session, |
|
| 417 cert_type_priority); |
|
| 418 |
414 |
| 419 gnutls_credentials_set(gnutls_data->session, GNUTLS_CRD_CERTIFICATE, |
415 gnutls_credentials_set(gnutls_data->session, GNUTLS_CRD_CERTIFICATE, |
| 420 xcred); |
416 xcred); |
| 421 |
417 |
| 422 gnutls_transport_set_ptr(gnutls_data->session, GINT_TO_POINTER(gsc->fd)); |
418 gnutls_transport_set_ptr(gnutls_data->session, GINT_TO_POINTER(gsc->fd)); |
| 517 return s; |
513 return s; |
| 518 } |
514 } |
| 519 |
515 |
| 520 /* Forward declarations are fun! */ |
516 /* Forward declarations are fun! */ |
| 521 static PurpleCertificate * |
517 static PurpleCertificate * |
| 522 x509_import_from_datum(const gnutls_datum dt, gnutls_x509_crt_fmt mode); |
518 x509_import_from_datum(const gnutls_datum_t dt, gnutls_x509_crt_fmt_t mode); |
| 523 /* indeed! */ |
519 /* indeed! */ |
| 524 static gboolean |
520 static gboolean |
| 525 x509_certificate_signed_by(PurpleCertificate * crt, |
521 x509_certificate_signed_by(PurpleCertificate * crt, |
| 526 PurpleCertificate * issuer); |
522 PurpleCertificate * issuer); |
| 527 static void |
523 static void |
| 535 |
531 |
| 536 /* List of Certificate instances to return */ |
532 /* List of Certificate instances to return */ |
| 537 GList * peer_certs = NULL; |
533 GList * peer_certs = NULL; |
| 538 |
534 |
| 539 /* List of raw certificates as given by GnuTLS */ |
535 /* List of raw certificates as given by GnuTLS */ |
| 540 const gnutls_datum *cert_list; |
536 const gnutls_datum_t *cert_list; |
| 541 unsigned int cert_list_size = 0; |
537 unsigned int cert_list_size = 0; |
| 542 |
538 |
| 543 unsigned int i; |
539 unsigned int i; |
| 544 |
540 |
| 545 /* This should never, ever happen. */ |
541 /* This should never, ever happen. */ |
| 583 static PurpleCertificateScheme x509_gnutls; |
579 static PurpleCertificateScheme x509_gnutls; |
| 584 |
580 |
| 585 /** Refcounted GnuTLS certificate data instance */ |
581 /** Refcounted GnuTLS certificate data instance */ |
| 586 typedef struct { |
582 typedef struct { |
| 587 gint refcount; |
583 gint refcount; |
| 588 gnutls_x509_crt crt; |
584 gnutls_x509_crt_t crt; |
| 589 } x509_crtdata_t; |
585 } x509_crtdata_t; |
| 590 |
586 |
| 591 /** Helper functions for reference counting */ |
587 /** Helper functions for reference counting */ |
| 592 static x509_crtdata_t * |
588 static x509_crtdata_t * |
| 593 x509_crtdata_addref(x509_crtdata_t *cd) |
589 x509_crtdata_addref(x509_crtdata_t *cd) |
| 625 * "over the wire" certs for SSL) |
621 * "over the wire" certs for SSL) |
| 626 * |
622 * |
| 627 * @return A newly allocated Certificate structure of the x509_gnutls scheme |
623 * @return A newly allocated Certificate structure of the x509_gnutls scheme |
| 628 */ |
624 */ |
| 629 static PurpleCertificate * |
625 static PurpleCertificate * |
| 630 x509_import_from_datum(const gnutls_datum dt, gnutls_x509_crt_fmt mode) |
626 x509_import_from_datum(const gnutls_datum_t dt, gnutls_x509_crt_fmt_t mode) |
| 631 { |
627 { |
| 632 /* Internal certificate data structure */ |
628 /* Internal certificate data structure */ |
| 633 x509_crtdata_t *certdat; |
629 x509_crtdata_t *certdat; |
| 634 /* New certificate to return */ |
630 /* New certificate to return */ |
| 635 PurpleCertificate * crt; |
631 PurpleCertificate * crt; |
| 660 x509_import_from_file(const gchar * filename) |
656 x509_import_from_file(const gchar * filename) |
| 661 { |
657 { |
| 662 PurpleCertificate *crt; /* Certificate being constructed */ |
658 PurpleCertificate *crt; /* Certificate being constructed */ |
| 663 gchar *buf; /* Used to load the raw file data */ |
659 gchar *buf; /* Used to load the raw file data */ |
| 664 gsize buf_sz; /* Size of the above */ |
660 gsize buf_sz; /* Size of the above */ |
| 665 gnutls_datum dt; /* Struct to pass down to GnuTLS */ |
661 gnutls_datum_t dt; /* Struct to pass down to GnuTLS */ |
| 666 |
662 |
| 667 purple_debug_info("gnutls", |
663 purple_debug_info("gnutls", |
| 668 "Attempting to load X.509 certificate from %s\n", |
664 "Attempting to load X.509 certificate from %s\n", |
| 669 filename); |
665 filename); |
| 670 |
666 |
| 703 PurpleCertificate *crt; /* Certificate being constructed */ |
699 PurpleCertificate *crt; /* Certificate being constructed */ |
| 704 gchar *buf; /* Used to load the raw file data */ |
700 gchar *buf; /* Used to load the raw file data */ |
| 705 gchar *begin, *end; |
701 gchar *begin, *end; |
| 706 GSList *crts = NULL; |
702 GSList *crts = NULL; |
| 707 gsize buf_sz; /* Size of the above */ |
703 gsize buf_sz; /* Size of the above */ |
| 708 gnutls_datum dt; /* Struct to pass down to GnuTLS */ |
704 gnutls_datum_t dt; /* Struct to pass down to GnuTLS */ |
| 709 |
705 |
| 710 purple_debug_info("gnutls", |
706 purple_debug_info("gnutls", |
| 711 "Attempting to load X.509 certificates from %s\n", |
707 "Attempting to load X.509 certificates from %s\n", |
| 712 filename); |
708 filename); |
| 713 |
709 |
| 749 * @return TRUE if success, otherwise FALSE |
745 * @return TRUE if success, otherwise FALSE |
| 750 */ |
746 */ |
| 751 static gboolean |
747 static gboolean |
| 752 x509_export_certificate(const gchar *filename, PurpleCertificate *crt) |
748 x509_export_certificate(const gchar *filename, PurpleCertificate *crt) |
| 753 { |
749 { |
| 754 gnutls_x509_crt crt_dat; /* GnuTLS cert struct */ |
750 gnutls_x509_crt_t crt_dat; /* GnuTLS cert struct */ |
| 755 int ret; |
751 int ret; |
| 756 gchar * out_buf; /* Data to output */ |
752 gchar * out_buf; /* Data to output */ |
| 757 size_t out_size; /* Output size */ |
753 size_t out_size; /* Output size */ |
| 758 gboolean success = FALSE; |
754 gboolean success = FALSE; |
| 759 |
755 |
| 855 */ |
851 */ |
| 856 static gboolean |
852 static gboolean |
| 857 x509_certificate_signed_by(PurpleCertificate * crt, |
853 x509_certificate_signed_by(PurpleCertificate * crt, |
| 858 PurpleCertificate * issuer) |
854 PurpleCertificate * issuer) |
| 859 { |
855 { |
| 860 gnutls_x509_crt crt_dat; |
856 gnutls_x509_crt_t crt_dat; |
| 861 gnutls_x509_crt issuer_dat; |
857 gnutls_x509_crt_t issuer_dat; |
| 862 unsigned int verify; /* used to store result from GnuTLS verifier */ |
858 unsigned int verify; /* used to store result from GnuTLS verifier */ |
| 863 int ret; |
859 int ret; |
| 864 gchar *crt_id = NULL; |
860 gchar *crt_id = NULL; |
| 865 gchar *issuer_id = NULL; |
861 gchar *issuer_id = NULL; |
| 866 |
862 |
| 961 static GByteArray * |
957 static GByteArray * |
| 962 x509_sha1sum(PurpleCertificate *crt) |
958 x509_sha1sum(PurpleCertificate *crt) |
| 963 { |
959 { |
| 964 size_t hashlen = 20; /* SHA1 hashes are 20 bytes */ |
960 size_t hashlen = 20; /* SHA1 hashes are 20 bytes */ |
| 965 size_t tmpsz = hashlen; /* Throw-away variable for GnuTLS to stomp on*/ |
961 size_t tmpsz = hashlen; /* Throw-away variable for GnuTLS to stomp on*/ |
| 966 gnutls_x509_crt crt_dat; |
962 gnutls_x509_crt_t crt_dat; |
| 967 GByteArray *hash; /**< Final hash container */ |
963 GByteArray *hash; /**< Final hash container */ |
| 968 guchar hashbuf[hashlen]; /**< Temporary buffer to contain hash */ |
964 guchar hashbuf[hashlen]; /**< Temporary buffer to contain hash */ |
| 969 |
965 |
| 970 g_return_val_if_fail(crt, NULL); |
966 g_return_val_if_fail(crt, NULL); |
| 971 |
967 |
| 972 crt_dat = X509_GET_GNUTLS_DATA(crt); |
968 crt_dat = X509_GET_GNUTLS_DATA(crt); |
| 973 |
969 |
| 974 /* Extract the fingerprint */ |
970 /* Extract the fingerprint */ |
| 975 g_return_val_if_fail( |
971 g_return_val_if_fail( |
| 976 0 == gnutls_x509_crt_get_fingerprint(crt_dat, GNUTLS_MAC_SHA, |
972 0 == gnutls_x509_crt_get_fingerprint(crt_dat, GNUTLS_DIG_SHA, |
| 977 hashbuf, &tmpsz), |
973 hashbuf, &tmpsz), |
| 978 NULL); |
974 NULL); |
| 979 |
975 |
| 980 /* This shouldn't happen */ |
976 /* This shouldn't happen */ |
| 981 g_return_val_if_fail(tmpsz == hashlen, NULL); |
977 g_return_val_if_fail(tmpsz == hashlen, NULL); |
| 988 } |
984 } |
| 989 |
985 |
| 990 static gchar * |
986 static gchar * |
| 991 x509_cert_dn (PurpleCertificate *crt) |
987 x509_cert_dn (PurpleCertificate *crt) |
| 992 { |
988 { |
| 993 gnutls_x509_crt cert_dat; |
989 gnutls_x509_crt_t cert_dat; |
| 994 gchar *dn = NULL; |
990 gchar *dn = NULL; |
| 995 size_t dn_size; |
991 size_t dn_size; |
| 996 |
992 |
| 997 g_return_val_if_fail(crt, NULL); |
993 g_return_val_if_fail(crt, NULL); |
| 998 g_return_val_if_fail(crt->scheme == &x509_gnutls, NULL); |
994 g_return_val_if_fail(crt->scheme == &x509_gnutls, NULL); |
| 1098 } |
1094 } |
| 1099 |
1095 |
| 1100 static gboolean |
1096 static gboolean |
| 1101 x509_check_name (PurpleCertificate *crt, const gchar *name) |
1097 x509_check_name (PurpleCertificate *crt, const gchar *name) |
| 1102 { |
1098 { |
| 1103 gnutls_x509_crt crt_dat; |
1099 gnutls_x509_crt_t crt_dat; |
| 1104 |
1100 |
| 1105 g_return_val_if_fail(crt, FALSE); |
1101 g_return_val_if_fail(crt, FALSE); |
| 1106 g_return_val_if_fail(crt->scheme == &x509_gnutls, FALSE); |
1102 g_return_val_if_fail(crt->scheme == &x509_gnutls, FALSE); |
| 1107 g_return_val_if_fail(name, FALSE); |
1103 g_return_val_if_fail(name, FALSE); |
| 1108 |
1104 |
| 1116 } |
1112 } |
| 1117 |
1113 |
| 1118 static gboolean |
1114 static gboolean |
| 1119 x509_times (PurpleCertificate *crt, time_t *activation, time_t *expiration) |
1115 x509_times (PurpleCertificate *crt, time_t *activation, time_t *expiration) |
| 1120 { |
1116 { |
| 1121 gnutls_x509_crt crt_dat; |
1117 gnutls_x509_crt_t crt_dat; |
| 1122 /* GnuTLS time functions return this on error */ |
1118 /* GnuTLS time functions return this on error */ |
| 1123 const time_t errval = (time_t) (-1); |
1119 const time_t errval = (time_t) (-1); |
| 1124 gboolean success = TRUE; |
1120 gboolean success = TRUE; |
| 1125 |
1121 |
| 1126 g_return_val_if_fail(crt, FALSE); |
1122 g_return_val_if_fail(crt, FALSE); |