=== modified file 'configure.in' --- configure.in 2008-04-08 21:37:12 +0000 +++ configure.in 2008-04-21 17:32:27 +0000 @@ -145,6 +145,11 @@ if test "$have_ssl" = "yes"; then AC_DEFINE(HAVE_SSL, 1, [Defined if you have SSL support]) SSL_REQUIREMENT="gnutls" + + old_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $LIBGNUTLS_LIBS $LIBGCRYPT_LIBS" + AC_CHECK_FUNCS(gnutls_certificate_client_set_sign_function) + LDFLAGS="$old_LDFLAGS" else if test "$enable_ssl" = "auto"; then AC_MSG_WARN(Disabling SSL support); === modified file 'libsoup/soup-gnutls.c' --- libsoup/soup-gnutls.c 2008-04-20 23:11:54 +0000 +++ libsoup/soup-gnutls.c 2008-04-21 17:32:27 +0000 @@ -41,6 +41,12 @@ struct SoupSSLCredentials { gnutls_certificate_credentials creds; gboolean have_ca_file; + +#ifdef HAVE_GNUTLS_CERTIFICATE_CLIENT_SET_SIGN_FUNCTION + SoupGnuTLSCertificateRequestFunc cert_func; + SoupGnuTLSSignDataFunc sign_func; + gpointer auth_data; +#endif }; typedef struct { @@ -419,6 +425,7 @@ gnutls_dh_set_prime_bits (session, DH_BITS); gnutls_transport_set_ptr (session, GINT_TO_POINTER (sockfd)); + gnutls_session_set_ptr (session, creds); chan = g_slice_new0 (SoupGNUTLSChannel); chan->fd = sockfd; @@ -462,6 +469,111 @@ } } +#ifdef HAVE_GNUTLS_CERTIFICATE_CLIENT_SET_SIGN_FUNCTION +static int +soup_ssl_retrieve_cert (gnutls_session_t session, + const gnutls_datum_t *req_ca_rdn, int nreqs, + const gnutls_pk_algorithm_t *sign_algos, + int sign_algos_length, gnutls_retr_st * st) +{ + SoupSSLCredentials *creds; + int cert_ret_len = 0; + gnutls_datum_t *cert_ret; + gnutls_x509_crt_t *gnutls_cert; + int i; + int ret; + + creds = gnutls_session_get_ptr (session); + if (!creds) + return -1; + + g_return_val_if_fail (creds->cert_func != NULL, -1); + + if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) + return -1; + + ret = creds->cert_func (req_ca_rdn, nreqs, + &cert_ret, &cert_ret_len, + creds->auth_data); + + if (ret != 0) + return -1; + + if (cert_ret_len == 0) + return 0; + + gnutls_cert = gnutls_malloc (sizeof (gnutls_x509_crt_t) * cert_ret_len); + for (i = 0; i < cert_ret_len; i++) { + if (ret == 0) { + gnutls_x509_crt_init (&gnutls_cert[i]); + ret = gnutls_x509_crt_import (gnutls_cert[i], + &cert_ret[i], + GNUTLS_X509_FMT_DER); + if (ret != 0) { + int j; + for (j = 0; i < i; j++) + gnutls_x509_crt_deinit (gnutls_cert[j]); + } + } + gnutls_free (cert_ret[i].data); + } + gnutls_free (cert_ret); + + if (ret != 0) { + gnutls_free (gnutls_cert); + return -1; + } + + st->type = GNUTLS_CRT_X509; + st->cert.x509 = gnutls_cert; + st->ncerts = cert_ret_len; + st->key.x509 = NULL; + st->deinit_all = 1; + + return 0; +} + +static int +soup_ssl_sign_data (gnutls_session_t session, + gnutls_datum_t * cert, + gnutls_certificate_type_t cert_type, + const gnutls_datum_t *hash_concat, + gnutls_datum_t * signature) +{ + SoupSSLCredentials *creds; + int ret; + + creds = gnutls_session_get_ptr (session); + if (!creds) + return -1; + + g_return_val_if_fail (creds->sign_func != NULL, -1); + g_return_val_if_fail (cert_type == GNUTLS_CRT_X509, -1); + + ret = creds->sign_func (cert, hash_concat, signature, + creds->auth_data); + + return ret; +} + +void +soup_gnutls_set_callbacks (SoupSSLCredentials *creds, + SoupGnuTLSCertificateRequestFunc cert_func, + SoupGnuTLSSignDataFunc sign_func, + gpointer user_data) +{ + creds->cert_func = cert_func; + creds->sign_func = sign_func; + creds->auth_data = user_data; + + if (cert_func) + gnutls_certificate_client_set_retrieve_function (creds->creds, soup_ssl_retrieve_cert); + + if (sign_func) + gnutls_certificate_client_set_sign_function (creds->creds, soup_ssl_sign_data); +} +#endif /* HAVE_GNUTLS_CERTIFICATE_CLIENT_SET_SIGN_FUNCTION */ + /** * soup_ssl_get_client_credentials: * @ca_file: path to a file containing X509-encoded Certificate === modified file 'libsoup/soup-marshal.list' --- libsoup/soup-marshal.list 2008-01-15 17:40:47 +0000 +++ libsoup/soup-marshal.list 2008-04-21 17:34:46 +0000 @@ -5,3 +5,5 @@ NONE:OBJECT,OBJECT NONE:OBJECT,POINTER NONE:OBJECT,OBJECT,BOOLEAN +INT:POINTER,INT,POINTER,POINTER +INT:POINTER,POINTER,POINTER === modified file 'libsoup/soup-session.c' --- libsoup/soup-session.c 2008-04-08 22:13:03 +0000 +++ libsoup/soup-session.c 2008-04-21 17:34:09 +0000 @@ -124,6 +124,8 @@ REQUEST_STARTED, REQUEST_UNQUEUED, AUTHENTICATE, + CERTIFICATE_REQUESTED, + SIGN_DATA, LAST_SIGNAL }; @@ -391,6 +393,35 @@ SOUP_TYPE_AUTH, G_TYPE_BOOLEAN); + /* This signal is not part of SoupSession's public API, and + * *will* disappear without warning in the future. + */ + signals[CERTIFICATE_REQUESTED] = + g_signal_new ("certificate-requested", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + soup_marshal_INT__POINTER_INT_POINTER_POINTER, + G_TYPE_INT, 4, + G_TYPE_POINTER, + G_TYPE_INT, + G_TYPE_POINTER, + G_TYPE_POINTER); + + /* This signal is not part of SoupSession's public API, and + * *will* disappear without warning in the future. + */ + signals[SIGN_DATA] = + g_signal_new ("sign-data", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, + soup_marshal_INT__POINTER_POINTER_POINTER, + G_TYPE_INT, 3, + G_TYPE_POINTER, + G_TYPE_POINTER, + G_TYPE_POINTER); + /* properties */ g_object_class_install_property ( object_class, PROP_PROXY_URI, @@ -701,6 +732,46 @@ /* Hosts */ +#ifdef HAVE_GNUTLS_CERTIFICATE_CLIENT_SET_SIGN_FUNCTION +static int +soup_session_ssl_certificate_requested (const gnutls_datum_t *req_ca_rdn, + int nreqs, + gnutls_datum_t **cert_ret, + int *cert_ret_len, + gpointer user_data) +{ + SoupSession *session = user_data; + int ret = 0; + + g_return_val_if_fail (SOUP_IS_SESSION (user_data), -1); + + g_signal_emit (session, signals[CERTIFICATE_REQUESTED], 0, + req_ca_rdn, nreqs, + cert_ret, cert_ret_len, + &ret); + + return ret; +} + +static int +soup_session_ssl_sign_data (gnutls_datum_t *cert_der, + const gnutls_datum_t *hash_data, + gnutls_datum_t *sign_data, + gpointer user_data) +{ + SoupSession *session = user_data; + int ret = 0; + + g_return_val_if_fail (SOUP_IS_SESSION (user_data), -1); + + g_signal_emit (session, signals[SIGN_DATA], 0, + cert_der, hash_data, sign_data, + &ret); + + return ret; +} +#endif + static SoupSessionHost * soup_session_host_new (SoupSession *session, SoupURI *source_uri) { @@ -714,6 +785,12 @@ !priv->ssl_creds) { priv->ssl_creds = soup_ssl_get_client_credentials (priv->ssl_ca_file); +#ifdef HAVE_GNUTLS_CERTIFICATE_CLIENT_SET_SIGN_FUNCTION + soup_gnutls_set_callbacks (priv->ssl_creds, + soup_session_ssl_certificate_requested, + soup_session_ssl_sign_data, + session); +#endif } return host; === modified file 'libsoup/soup-ssl.h' --- libsoup/soup-ssl.h 2008-04-20 23:11:54 +0000 +++ libsoup/soup-ssl.h 2008-04-21 17:32:27 +0000 @@ -28,4 +28,24 @@ const char *remote_host, SoupSSLCredentials *creds); +#ifdef HAVE_GNUTLS_CERTIFICATE_CLIENT_SET_SIGN_FUNCTION +#include + +typedef int (*SoupGnuTLSCertificateRequestFunc) (const gnutls_datum_t *req_ca_rdn, + int nreqs, + gnutls_datum_t **cert_ret, + int *cert_ret_len, + gpointer user_data); + +typedef int (*SoupGnuTLSSignDataFunc) (gnutls_datum_t *cert_der, + const gnutls_datum_t *hash_data, + gnutls_datum_t *sign_data, + gpointer user_data); + +void soup_gnutls_set_callbacks (SoupSSLCredentials *creds, + SoupGnuTLSCertificateRequestFunc cert_func, + SoupGnuTLSSignDataFunc sign_func, + gpointer user_data); +#endif /* HAVE_GNUTLS... */ + #endif /* SOUP_SSL_H */