diff options
author | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-01-04 16:07:55 +0100 |
---|---|---|
committer | Schanzenbach, Martin <martin.schanzenbach@aisec.fraunhofer.de> | 2018-01-04 16:07:55 +0100 |
commit | 056ca89d207cd1865a90fe3fcd430a4381097da5 (patch) | |
tree | 928a3f7bf520ec99ac1bdbceb423dd68d375acbb | |
parent | b4f6c5a8b521d4942d19f5a34929bebaa60a6210 (diff) | |
parent | 78705d5a49d7066a01b832546d2507456a3c5d2c (diff) |
Merge remote-tracking branch 'origin/identity_abe'
78 files changed, 14264 insertions, 3795 deletions
@@ -15,8 +15,11 @@ GNU package (http://www.gnu.org/). This is an ALPHA release. There are known and significant bugs as well as many missing features in this release. +GNUnet is free software released under the GNU General Public License +(v3 or later). For details see the COPYING file in this directory. + Additional documentation about GNUnet can be found at -https://gnunet.org/. +https://gnunet.org/ and in the doc/ folder. Dependencies: @@ -63,6 +66,8 @@ How to install? The fastest way is to use a binary package if it is available for your system. For a more detailed description, read the installation instructions on the webpage at https://gnunet.org/installation. +Generic installation instructions are in the INSTALL file in this +directory. Note that some functions of GNUnet require "root" access. GNUnet will install (tiny) SUID binaries for those functions is you run "make @@ -300,7 +305,7 @@ Stay tuned * https://gnunet.org/ * https://gnunet.org/bugs/ -* https://gnunet.org/svn/ +* https://gnunet.org/git/ * http://www.gnu.org/software/gnunet/ * http://mail.gnu.org/mailman/listinfo/gnunet-developers * http://mail.gnu.org/mailman/listinfo/help-gnunet diff --git a/configure.ac b/configure.ac index eae03b01b..017b4836c 100644 --- a/configure.ac +++ b/configure.ac @@ -446,6 +446,27 @@ AC_CHECK_LIB(ogg, ogg_stream_flush_fill, ogg=0) +PKG_CHECK_MODULES([GLIB], [glib-2.0]) +# check for pbc library +pbc=0 +AC_CHECK_HEADER([pbc/pbc.h],pbc=1) +AC_CHECK_HEADER([gabe.h],abe=1) +AM_CONDITIONAL(HAVE_PBC, [test "$pbc" = 1]) +AM_CONDITIONAL(HAVE_ABE, [test "$abe" = 1]) +if test "x$pbc" = x1 +then + AC_DEFINE([HAVE_PBC],[1],[Have pbc library]) +else + AC_DEFINE([HAVE_PBC],[0],[Lacking pbc library]) +fi +if test "x$abe" = x1 +then + AC_DEFINE([HAVE_ABE],[1],[Have ABE library]) +else + AC_DEFINE([HAVE_ABE],[0],[Lacking ABE library]) +fi + + gst=0 PKG_CHECK_MODULES( @@ -1570,6 +1591,8 @@ src/gnsrecord/Makefile src/hello/Makefile src/identity/Makefile src/identity/identity.conf +src/credential/Makefile +src/credential/credential.conf src/include/Makefile src/integration-tests/Makefile src/json/Makefile @@ -1635,6 +1658,8 @@ src/vpn/vpn.conf src/zonemaster/Makefile src/zonemaster/zonemaster.conf src/rest/Makefile +src/abe/Makefile +src/identity-attribute/Makefile src/identity-provider/Makefile pkgconfig/Makefile pkgconfig/gnunetarm.pc diff --git a/contrib/Dockerfile b/contrib/Dockerfile new file mode 100644 index 000000000..5a193a46d --- /dev/null +++ b/contrib/Dockerfile @@ -0,0 +1,63 @@ +from fedora:26 + +# Install the required build tools +RUN dnf -y update && dnf -y install which git automake texinfo gettext-devel autoconf libtool libtool-ltdl-devel libidn-devel libunistring-devel glpk libextractor-devel libmicrohttpd-devel gnutls libgcrypt-devel jansson-devel sqlite-devel npm + +WORKDIR /usr/src + +# Install gnurl from source at version gnurl-7.54.0 +RUN git clone https://git.taler.net/gnurl.git --branch gnurl-7.54.0 +WORKDIR /usr/src/gnurl +RUN autoreconf -i +RUN ./configure --enable-ipv6 --with-gnutls --without-libssh2 \ +--without-libmetalink --without-winidn --without-librtmp \ +--without-nghttp2 --without-nss --without-cyassl \ +--without-polarssl --without-ssl --without-winssl \ +--without-darwinssl --disable-sspi --disable-ntlm-wb --disable-ldap \ +--disable-rtsp --disable-dict --disable-telnet --disable-tftp \ +--disable-pop3 --disable-imap --disable-smtp --disable-gopher \ +--disable-file --disable-ftp --disable-smb +RUN make install +WORKDIR /usr/src + +RUN dnf -y install wget flex bison + +# Install libpbc +RUN wget https://crypto.stanford.edu/pbc/files/pbc-0.5.14.tar.gz +RUN tar xvzpf pbc-0.5.14.tar.gz +WORKDIR /usr/src/pbc-0.5.14 +RUN ./configure --prefix=/usr +RUN make install +WORKDIR /usr/src + +RUN dnf -y install glib2-devel + +# Install libbswabe +RUN git clone https://github.com/schanzen/libgabe.git +WORKDIR /usr/src/libgabe +RUN ./configure --prefix=/usr +RUN make install + +# Install WebUI +WORKDIR /usr/src/ +RUN git clone https://github.com/schanzen/gnunet-webui.git +WORKDIR /usr/src/gnunet-webui +RUN git checkout gnuidentity + +RUN mkdir /usr/src/gnunet +WORKDIR /usr/src/gnunet +ADD . . +ARG NUM_JOBS +RUN ./bootstrap +RUN ./configure --prefix=/usr/local +RUN make -j$NUM_JOBS +RUN make install + +RUN groupadd gnunetdns +RUN adduser --system -m --home-dir /var/lib/gnunet gnunet +RUN chown gnunet:gnunet /var/lib/gnunet +RUN echo '[arm]\nSYSTEM_ONLY = YES\nUSER_ONLY = NO\n' > /etc/gnunet.conf + +ADD docker-entrypoint.sh . + +CMD ["sh", "docker-entrypoint.sh"] diff --git a/contrib/docker-entrypoint.sh b/contrib/docker-entrypoint.sh new file mode 100644 index 000000000..807d86d6f --- /dev/null +++ b/contrib/docker-entrypoint.sh @@ -0,0 +1,3 @@ +#!/bin/bash +gnunet-arm -s > $HOME/gnunet.log 2>&1 +exec bash
\ No newline at end of file diff --git a/po/POTFILES.in b/po/POTFILES.in index 4a4cfbd96..2fcb74c09 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,15 +1,24 @@ +src/abe/abe.c src/arm/arm_api.c src/arm/arm_monitor_api.c src/arm/gnunet-arm.c src/arm/gnunet-service-arm.c src/arm/mockup-service.c +src/ats-tests/ats-testing-experiment.c +src/ats-tests/ats-testing-log.c +src/ats-tests/ats-testing-preferences.c +src/ats-tests/ats-testing-traffic.c +src/ats-tests/ats-testing.c +src/ats-tests/gnunet-ats-sim.c +src/ats-tests/gnunet-solver-eval.c +src/ats-tool/gnunet-ats.c src/ats/ats_api_connectivity.c src/ats/ats_api_performance.c src/ats/ats_api_scanner.c src/ats/ats_api_scheduling.c src/ats/gnunet-ats-solver-eval.c -src/ats/gnunet-service-ats_addresses.c src/ats/gnunet-service-ats.c +src/ats/gnunet-service-ats_addresses.c src/ats/gnunet-service-ats_connectivity.c src/ats/gnunet-service-ats_normalization.c src/ats/gnunet-service-ats_performance.c @@ -20,14 +29,6 @@ src/ats/gnunet-service-ats_scheduling.c src/ats/plugin_ats_mlp.c src/ats/plugin_ats_proportional.c src/ats/plugin_ats_ril.c -src/ats-tests/ats-testing.c -src/ats-tests/ats-testing-experiment.c -src/ats-tests/ats-testing-log.c -src/ats-tests/ats-testing-preferences.c -src/ats-tests/ats-testing-traffic.c -src/ats-tests/gnunet-ats-sim.c -src/ats-tests/gnunet-solver-eval.c -src/ats-tool/gnunet-ats.c src/auction/gnunet-auction-create.c src/auction/gnunet-auction-info.c src/auction/gnunet-auction-join.c @@ -39,8 +40,8 @@ src/block/plugin_block_test.c src/cadet/cadet_api.c src/cadet/cadet_test_lib.c src/cadet/desirability_table.c -src/cadet/gnunet-cadet.c src/cadet/gnunet-cadet-profiler.c +src/cadet/gnunet-cadet.c src/cadet/gnunet-service-cadet.c src/cadet/gnunet-service-cadet_channel.c src/cadet/gnunet-service-cadet_connection.c @@ -56,15 +57,15 @@ src/consensus/gnunet-service-consensus.c src/consensus/plugin_block_consensus.c src/conversation/conversation_api.c src/conversation/conversation_api_call.c -src/conversation/gnunet-conversation.c src/conversation/gnunet-conversation-test.c -src/conversation/gnunet_gst.c -src/conversation/gnunet_gst_test.c -src/conversation/gnunet-helper-audio-playback.c +src/conversation/gnunet-conversation.c src/conversation/gnunet-helper-audio-playback-gst.c -src/conversation/gnunet-helper-audio-record.c +src/conversation/gnunet-helper-audio-playback.c src/conversation/gnunet-helper-audio-record-gst.c +src/conversation/gnunet-helper-audio-record.c src/conversation/gnunet-service-conversation.c +src/conversation/gnunet_gst.c +src/conversation/gnunet_gst_test.c src/conversation/microphone.c src/conversation/plugin_gnsrecord_conversation.c src/conversation/speaker.c @@ -75,6 +76,13 @@ src/core/gnunet-service-core.c src/core/gnunet-service-core_kx.c src/core/gnunet-service-core_sessions.c src/core/gnunet-service-core_typemap.c +src/credential/credential_api.c +src/credential/credential_misc.c +src/credential/credential_serialization.c +src/credential/gnunet-credential.c +src/credential/gnunet-service-credential.c +src/credential/plugin_gnsrecord_credential.c +src/credential/plugin_rest_credential.c src/curl/curl.c src/curl/curl_reschedule.c src/datacache/datacache.c @@ -94,7 +102,6 @@ src/dht/dht_api.c src/dht/dht_test_lib.c src/dht/gnunet-dht-get.c src/dht/gnunet-dht-monitor.c -src/dht/gnunet_dht_profiler.c src/dht/gnunet-dht-put.c src/dht/gnunet-service-dht.c src/dht/gnunet-service-dht_clients.c @@ -103,6 +110,7 @@ src/dht/gnunet-service-dht_hello.c src/dht/gnunet-service-dht_neighbours.c src/dht/gnunet-service-dht_nse.c src/dht/gnunet-service-dht_routing.c +src/dht/gnunet_dht_profiler.c src/dht/plugin_block_dht.c src/dns/dns_api.c src/dns/dnsparser.c @@ -117,8 +125,8 @@ src/dv/gnunet-dv.c src/dv/gnunet-service-dv.c src/dv/plugin_transport_dv.c src/exit/gnunet-daemon-exit.c -src/exit/gnunet-helper-exit.c src/exit/gnunet-helper-exit-windows.c +src/exit/gnunet-helper-exit.c src/fragmentation/defragmentation.c src/fragmentation/fragmentation.c src/fs/fs_api.c @@ -143,8 +151,8 @@ src/fs/gnunet-auto-share.c src/fs/gnunet-daemon-fsprofiler.c src/fs/gnunet-directory.c src/fs/gnunet-download.c -src/fs/gnunet-fs.c src/fs/gnunet-fs-profiler.c +src/fs/gnunet-fs.c src/fs/gnunet-helper-fs-publish.c src/fs/gnunet-publish.c src/fs/gnunet-search.c @@ -162,10 +170,10 @@ src/fs/plugin_block_fs.c src/gns/gns_api.c src/gns/gnunet-bcd.c src/gns/gnunet-dns2gns.c -src/gns/gnunet-gns.c src/gns/gnunet-gns-helper-service-w32.c src/gns/gnunet-gns-import.c src/gns/gnunet-gns-proxy.c +src/gns/gnunet-gns.c src/gns/gnunet-service-gns.c src/gns/gnunet-service-gns_interceptor.c src/gns/gnunet-service-gns_resolver.c @@ -174,41 +182,44 @@ src/gns/nss/nss_gns_query.c src/gns/plugin_block_gns.c src/gns/plugin_gnsrecord_gns.c src/gns/plugin_rest_gns.c +src/gns/w32nsp-install.c +src/gns/w32nsp-resolve.c +src/gns/w32nsp-uninstall.c +src/gns/w32nsp.c src/gnsrecord/gnsrecord.c src/gnsrecord/gnsrecord_crypto.c src/gnsrecord/gnsrecord_misc.c src/gnsrecord/gnsrecord_serialization.c src/gnsrecord/plugin_gnsrecord_dns.c -src/gns/w32nsp.c -src/gns/w32nsp-install.c -src/gns/w32nsp-resolve.c -src/gns/w32nsp-uninstall.c src/hello/address.c src/hello/gnunet-hello.c src/hello/hello.c src/hostlist/gnunet-daemon-hostlist.c src/hostlist/gnunet-daemon-hostlist_client.c src/hostlist/gnunet-daemon-hostlist_server.c +src/identity-attribute/identity_attribute.c +src/identity-attribute/plugin_identity_attribute_gnuid.c +src/identity-provider/gnunet-idp.c +src/identity-provider/gnunet-service-identity-provider.c +src/identity-provider/identity_provider_api.c +src/identity-provider/jwt.c +src/identity-provider/plugin_gnsrecord_identity_provider.c +src/identity-provider/plugin_identity_provider_sqlite.c +src/identity-provider/plugin_rest_identity_provider.c src/identity/gnunet-identity.c src/identity/gnunet-service-identity.c src/identity/identity_api.c src/identity/identity_api_lookup.c -src/identity/plugin_gnsrecord_identity.c src/identity/plugin_rest_identity.c -src/identity-provider/gnunet-identity-token.c -src/identity-provider/gnunet-service-identity-provider.c -src/identity-provider/identity_provider_api.c -src/identity-provider/identity_token.c -src/identity-provider/plugin_rest_identity_provider.c +src/json/json.c +src/json/json_generator.c +src/json/json_helper.c +src/json/json_mhd.c src/jsonapi/jsonapi.c src/jsonapi/jsonapi_document.c src/jsonapi/jsonapi_error.c src/jsonapi/jsonapi_relationship.c src/jsonapi/jsonapi_resource.c -src/json/json.c -src/json/json_generator.c -src/json/json_helper.c -src/json/json_mhd.c src/multicast/gnunet-multicast.c src/multicast/gnunet-service-multicast.c src/multicast/multicast_api.c @@ -222,8 +233,8 @@ src/namecache/namecache_api.c src/namecache/plugin_namecache_flat.c src/namecache/plugin_namecache_postgres.c src/namecache/plugin_namecache_sqlite.c -src/namestore/gnunet-namestore.c src/namestore/gnunet-namestore-fcfsd.c +src/namestore/gnunet-namestore.c src/namestore/gnunet-service-namestore.c src/namestore/namestore_api.c src/namestore/namestore_api_monitor.c @@ -238,10 +249,10 @@ src/nat-auto/gnunet-service-nat-auto.c src/nat-auto/gnunet-service-nat-auto_legacy.c src/nat-auto/nat_auto_api.c src/nat-auto/nat_auto_api_test.c -src/nat/gnunet-helper-nat-client.c src/nat/gnunet-helper-nat-client-windows.c -src/nat/gnunet-helper-nat-server.c +src/nat/gnunet-helper-nat-client.c src/nat/gnunet-helper-nat-server-windows.c +src/nat/gnunet-helper-nat-server.c src/nat/gnunet-nat.c src/nat/gnunet-service-nat.c src/nat/gnunet-service-nat_externalip.c @@ -250,15 +261,15 @@ src/nat/gnunet-service-nat_mini.c src/nat/gnunet-service-nat_stun.c src/nat/nat_api.c src/nat/nat_api_stun.c -src/nse/gnunet-nse.c src/nse/gnunet-nse-profiler.c +src/nse/gnunet-nse.c src/nse/gnunet-service-nse.c src/nse/nse_api.c +src/peerinfo-tool/gnunet-peerinfo.c +src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerinfo/gnunet-service-peerinfo.c src/peerinfo/peerinfo_api.c src/peerinfo/peerinfo_api_notify.c -src/peerinfo-tool/gnunet-peerinfo.c -src/peerinfo-tool/gnunet-peerinfo_plugins.c src/peerstore/gnunet-peerstore.c src/peerstore/gnunet-service-peerstore.c src/peerstore/peerstore_api.c @@ -309,13 +320,13 @@ src/rps/gnunet-service-rps_custommap.c src/rps/gnunet-service-rps_sampler.c src/rps/gnunet-service-rps_sampler_elem.c src/rps/gnunet-service-rps_view.c -src/rps/rps_api.c src/rps/rps-test_util.c +src/rps/rps_api.c src/scalarproduct/gnunet-scalarproduct.c -src/scalarproduct/gnunet-service-scalarproduct_alice.c -src/scalarproduct/gnunet-service-scalarproduct_bob.c src/scalarproduct/gnunet-service-scalarproduct-ecc_alice.c src/scalarproduct/gnunet-service-scalarproduct-ecc_bob.c +src/scalarproduct/gnunet-service-scalarproduct_alice.c +src/scalarproduct/gnunet-service-scalarproduct_bob.c src/scalarproduct/scalarproduct_api.c src/secretsharing/gnunet-secretsharing-profiler.c src/secretsharing/gnunet-service-secretsharing.c @@ -342,15 +353,16 @@ src/statistics/gnunet-statistics.c src/statistics/statistics_api.c src/template/gnunet-service-template.c src/template/gnunet-template.c +src/testbed-logger/gnunet-service-testbed-logger.c +src/testbed-logger/testbed_logger_api.c src/testbed/generate-underlay-topology.c src/testbed/gnunet-daemon-latency-logger.c src/testbed/gnunet-daemon-testbed-blacklist.c src/testbed/gnunet-daemon-testbed-underlay.c src/testbed/gnunet-helper-testbed.c -src/testbed/gnunet_mpi_test.c src/testbed/gnunet-service-test-barriers.c -src/testbed/gnunet-service-testbed_barriers.c src/testbed/gnunet-service-testbed.c +src/testbed/gnunet-service-testbed_barriers.c src/testbed/gnunet-service-testbed_cache.c src/testbed/gnunet-service-testbed_connectionpool.c src/testbed/gnunet-service-testbed_cpustatus.c @@ -358,20 +370,19 @@ src/testbed/gnunet-service-testbed_links.c src/testbed/gnunet-service-testbed_meminfo.c src/testbed/gnunet-service-testbed_oc.c src/testbed/gnunet-service-testbed_peers.c -src/testbed/gnunet_testbed_mpi_spawn.c src/testbed/gnunet-testbed-profiler.c -src/testbed-logger/gnunet-service-testbed-logger.c -src/testbed-logger/testbed_logger_api.c -src/testbed/testbed_api_barriers.c +src/testbed/gnunet_mpi_test.c +src/testbed/gnunet_testbed_mpi_spawn.c src/testbed/testbed_api.c +src/testbed/testbed_api_barriers.c src/testbed/testbed_api_hosts.c src/testbed/testbed_api_operations.c src/testbed/testbed_api_peers.c src/testbed/testbed_api_sd.c src/testbed/testbed_api_services.c src/testbed/testbed_api_statistics.c -src/testbed/testbed_api_testbed.c src/testbed/testbed_api_test.c +src/testbed/testbed_api_testbed.c src/testbed/testbed_api_topology.c src/testbed/testbed_api_underlay.c src/testing/gnunet-testing.c @@ -380,34 +391,39 @@ src/testing/testing.c src/topology/friends.c src/topology/gnunet-daemon-topology.c src/transport/gnunet-helper-transport-bluetooth.c -src/transport/gnunet-helper-transport-wlan.c src/transport/gnunet-helper-transport-wlan-dummy.c -src/transport/gnunet-service-transport_ats.c +src/transport/gnunet-helper-transport-wlan.c src/transport/gnunet-service-transport.c +src/transport/gnunet-service-transport_ats.c src/transport/gnunet-service-transport_hello.c src/transport/gnunet-service-transport_manipulation.c src/transport/gnunet-service-transport_neighbours.c src/transport/gnunet-service-transport_plugins.c src/transport/gnunet-service-transport_validation.c -src/transport/gnunet-transport.c src/transport/gnunet-transport-certificate-creation.c src/transport/gnunet-transport-profiler.c src/transport/gnunet-transport-wlan-receiver.c src/transport/gnunet-transport-wlan-sender.c +src/transport/gnunet-transport.c src/transport/plugin_transport_http_client.c src/transport/plugin_transport_http_common.c src/transport/plugin_transport_http_server.c src/transport/plugin_transport_smtp.c src/transport/plugin_transport_tcp.c src/transport/plugin_transport_template.c -src/transport/plugin_transport_udp_broadcasting.c src/transport/plugin_transport_udp.c +src/transport/plugin_transport_udp_broadcasting.c src/transport/plugin_transport_unix.c src/transport/plugin_transport_wlan.c src/transport/tcp_connection_legacy.c src/transport/tcp_server_legacy.c src/transport/tcp_server_mst_legacy.c src/transport/tcp_service_legacy.c +src/transport/transport-testing-filenames.c +src/transport/transport-testing-loggers.c +src/transport/transport-testing-main.c +src/transport/transport-testing-send.c +src/transport/transport-testing.c src/transport/transport_api_address_to_string.c src/transport/transport_api_blacklist.c src/transport/transport_api_core.c @@ -416,11 +432,6 @@ src/transport/transport_api_manipulation.c src/transport/transport_api_monitor_peers.c src/transport/transport_api_monitor_plugins.c src/transport/transport_api_offer_hello.c -src/transport/transport-testing.c -src/transport/transport-testing-filenames.c -src/transport/transport-testing-loggers.c -src/transport/transport-testing-main.c -src/transport/transport-testing-send.c src/tun/regex.c src/tun/tun.c src/util/bandwidth.c @@ -434,10 +445,11 @@ src/util/configuration_loader.c src/util/container_bloomfilter.c src/util/container_heap.c src/util/container_meta_data.c -src/util/container_multihashmap32.c src/util/container_multihashmap.c +src/util/container_multihashmap32.c src/util/container_multipeermap.c src/util/container_multishortmap.c +src/util/crypto_abe.c src/util/crypto_crc.c src/util/crypto_ecc.c src/util/crypto_ecc_dlog.c @@ -454,8 +466,8 @@ src/util/crypto_symmetric.c src/util/disk.c src/util/getopt.c src/util/getopt_helpers.c -src/util/gnunet-config.c src/util/gnunet-config-diff.c +src/util/gnunet-config.c src/util/gnunet-ecc.c src/util/gnunet-helper-w32-console.c src/util/gnunet-resolver.c @@ -486,8 +498,8 @@ src/util/time.c src/util/w32cat.c src/util/win.c src/util/winproc.c -src/vpn/gnunet-helper-vpn.c src/vpn/gnunet-helper-vpn-windows.c +src/vpn/gnunet-helper-vpn.c src/vpn/gnunet-service-vpn.c src/vpn/gnunet-vpn.c src/vpn/vpn_api.c diff --git a/src/Makefile.am b/src/Makefile.am index 7f1a00177..6d0284157 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,11 +12,12 @@ endif if HAVE_EXPERIMENTAL EXP_DIR = \ rps -endif - -if HAVE_JSON -if HAVE_MHD - PROVIDER_DIR = identity-provider +# dv (FTBFS) +if HAVE_ABE + EXP_DIR += abe \ + credential \ + identity-attribute \ + identity-provider endif endif @@ -128,7 +129,6 @@ SUBDIRS = \ psyc \ social \ $(AUCTION_DIR) \ - $(EXP_DIR) \ - $(PROVIDER_DIR) + $(EXP_DIR) endif diff --git a/src/abe/Makefile.am b/src/abe/Makefile.am new file mode 100644 index 000000000..308e6c67c --- /dev/null +++ b/src/abe/Makefile.am @@ -0,0 +1,50 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +libexecdir= $(pkglibdir)/libexec/ + +pkgcfgdir= $(pkgdatadir)/config.d/ + +dist_pkgcfg_DATA = \ + abe.conf + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +libgnunetabe_la_SOURCES = abe.c + +libgnunetabe_la_LIBADD = \ + $(GCLIBADD)\ + $(LIBGCRYPT_LIBS) \ + $(LTLIBICONV) \ + $(LTLIBINTL) \ + $(ABE_LIBADD) \ + -lgabe \ + -lpbc \ + -lglib-2.0 \ + -lltdl $(Z_LIBS) -lunistring $(XLIB) + +libgnunetabe_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) \ + -version-info 1:0:0 + +lib_LTLIBRARIES = libgnunetabe.la + +if ENABLE_TEST_RUN +AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; +TESTS = $(check_PROGRAMS) +endif + +check_PROGRAMS = test_cpabe + +test_cpabe_SOURCES = \ + test_cpabe.c +test_cpabe_LDADD = \ + libgnunetabe.la \ + $(top_builddir)/src/util/libgnunetutil.la +check_PROGRAMS += \ + test_cpabe diff --git a/src/abe/abe.c b/src/abe/abe.c new file mode 100644 index 000000000..3f1f6dc5b --- /dev/null +++ b/src/abe/abe.c @@ -0,0 +1,499 @@ +/* + This file is part of GNUnet. Copyright (C) 2001-2018 Christian Grothoff + (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +/** + * @file abe/abe.c + * @brief functions for Attribute-Based Encryption + * @author Martin Schanzenbach + */ + + +#include "platform.h" +#include <pbc/pbc.h> +#include <gabe.h> + +#include "gnunet_crypto_lib.h" +#include "gnunet_abe_lib.h" + +struct GNUNET_ABE_AbeMasterKey +{ + gabe_pub_t* pub; + gabe_msk_t* msk; +}; + +struct GNUNET_ABE_AbeKey +{ + gabe_pub_t* pub; + gabe_prv_t* prv; +}; + +static int +init_aes( element_t k, int enc, + gcry_cipher_hd_t* handle, + struct GNUNET_CRYPTO_SymmetricSessionKey *key, + unsigned char* iv) +{ + int rc; + int key_len; + unsigned char* key_buf; + + key_len = element_length_in_bytes(k) < 33 ? 3 : element_length_in_bytes(k); + key_buf = (unsigned char*) malloc(key_len); + element_to_bytes(key_buf, k); + + memcpy (key->aes_key, key_buf, GNUNET_CRYPTO_AES_KEY_LENGTH); + GNUNET_assert (0 == + gcry_cipher_open (handle, GCRY_CIPHER_AES256, + GCRY_CIPHER_MODE_CFB, 0)); + rc = gcry_cipher_setkey (*handle, + key->aes_key, + sizeof (key->aes_key)); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + memset (iv, 0, 16); //TODO make reasonable + rc = gcry_cipher_setiv (*handle, + iv, + 16); + GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); + + free(key_buf); + return rc; +} + +static int +aes_128_cbc_encrypt( char* pt, + int size, + element_t k, + char **ct ) +{ + gcry_cipher_hd_t handle; + struct GNUNET_CRYPTO_SymmetricSessionKey skey; + unsigned char iv[16]; + char* buf; + int padding; + int buf_size; + uint8_t len[4]; + init_aes(k, 1, &handle, &skey, iv); + + /* TODO make less crufty */ + + /* stuff in real length (big endian) before padding */ + len[0] = (size & 0xff000000)>>24; + len[1] = (size & 0xff0000)>>16; + len[2] = (size & 0xff00)>>8; + len[3] = (size & 0xff)>>0; + padding = 16 - ((4+size) % 16); + buf_size = 4 + size + padding; + buf = GNUNET_malloc (buf_size); + GNUNET_memcpy (buf, len, 4); + GNUNET_memcpy (buf+4, pt, size); + *ct = GNUNET_malloc (buf_size); + + GNUNET_assert (0 == gcry_cipher_encrypt (handle, *ct, buf_size, buf, buf_size)); + gcry_cipher_close (handle); + //AES_cbc_encrypt(pt->data, ct->data, pt->len, &key, iv, AES_ENCRYPT); + GNUNET_free (buf); + return buf_size; +} + +static int +aes_128_cbc_decrypt( char* ct, + int size, + element_t k, + char **pt ) +{ + struct GNUNET_CRYPTO_SymmetricSessionKey skey; + gcry_cipher_hd_t handle; + unsigned char iv[16]; + char* tmp; + uint32_t len; + + init_aes(k, 1, &handle, &skey, iv); + + tmp = GNUNET_malloc (size); + + //AES_cbc_encrypt(ct->data, pt->data, ct->len, &key, iv, AES_DECRYPT); + GNUNET_assert (0 == gcry_cipher_decrypt (handle, tmp, size, ct, size)); + gcry_cipher_close (handle); + /* TODO make less crufty */ + + /* get real length */ + len = 0; + len = len + | ((tmp[0])<<24) | ((tmp[1])<<16) + | ((tmp[2])<<8) | ((tmp[3])<<0); + /* truncate any garbage from the padding */ + *pt = GNUNET_malloc (len); + GNUNET_memcpy (*pt, tmp+4, len); + GNUNET_free (tmp); + return len; +} + +/** + * @ingroup abe + * Create a new CP-ABE master key. Caller must free return value. + * + * @return fresh private key; free using #GNUNET_ABE_cpabe_delete_master_key + */ +struct GNUNET_ABE_AbeMasterKey* +GNUNET_ABE_cpabe_create_master_key (void) +{ + struct GNUNET_ABE_AbeMasterKey* key; + key = GNUNET_new (struct GNUNET_ABE_AbeMasterKey); + gabe_setup(&key->pub, &key->msk); + GNUNET_assert (NULL != key->pub); + GNUNET_assert (NULL != key->msk); + return key; +} + +/** + * @ingroup abe + * Delete a CP-ABE master key. + * + * @param key the master key + * @return fresh private key; free using #GNUNET_free + */ +void +GNUNET_ABE_cpabe_delete_master_key (struct GNUNET_ABE_AbeMasterKey *key) +{ + gabe_msk_free (key->msk); + gabe_pub_free (key->pub); + //GNUNET_free (key->msk); + //gabe_msk_free (key->msk); //For some reason free of pub implicit? + GNUNET_free (key); +} + +/** + * @ingroup abe + * Create a new CP-ABE key. Caller must free return value. + * + * @param key the master key + * @param attrs the attributes to append to the key + * @return fresh private key; free using #GNUNET_ABE_cpabe_delete_key + */ +struct GNUNET_ABE_AbeKey* +GNUNET_ABE_cpabe_create_key (struct GNUNET_ABE_AbeMasterKey *key, + char **attrs) +{ + struct GNUNET_ABE_AbeKey *prv_key; + int size; + char *tmp; + + prv_key = GNUNET_new (struct GNUNET_ABE_AbeKey); + prv_key->prv = gabe_keygen(key->pub, key->msk, attrs); + size = gabe_pub_serialize(key->pub, &tmp); + prv_key->pub = gabe_pub_unserialize(tmp, size); + GNUNET_free (tmp); + GNUNET_assert (NULL != prv_key->prv); + return prv_key; +} + +/** + * @ingroup abe + * Delete a CP-ABE key. + * + * @param key the key to delete + * @param delete_pub GNUNE_YES if the public key should also be freed (bug in gabe) + * @return fresh private key; free using #GNUNET_free + */ +void +GNUNET_ABE_cpabe_delete_key (struct GNUNET_ABE_AbeKey *key, + int delete_pub) +{ + //Memory management in gabe is buggy + gabe_prv_free (key->prv); + if (GNUNET_YES == delete_pub) + gabe_pub_free (key->pub); + GNUNET_free (key); +} + +static ssize_t +write_cpabe (void **result, + uint32_t file_len, + char* cph_buf, + int cph_buf_len, + char* aes_buf, + int aes_buf_len) +{ + char *ptr; + uint32_t *len; + + *result = GNUNET_malloc (12 + cph_buf_len + aes_buf_len); + ptr = *result; + len = (uint32_t*) ptr; + *len = htonl (file_len); + ptr += 4; + len = (uint32_t*) ptr; + *len = htonl (aes_buf_len); + ptr += 4; + memcpy (ptr, aes_buf, aes_buf_len); + ptr += aes_buf_len; + len = (uint32_t*) ptr; + *len = htonl (cph_buf_len); + ptr += 4; + memcpy (ptr, cph_buf, cph_buf_len); + return 12 + cph_buf_len + aes_buf_len; +} + +static ssize_t +read_cpabe (const void *data, + char** cph_buf, + int *cph_buf_len, + char** aes_buf, + int *aes_buf_len) +{ + int buf_len; + char *ptr; + uint32_t *len; + + ptr = (char*)data; + len = (uint32_t*)ptr; + buf_len = ntohl (*len); + ptr += 4; + len = (uint32_t*)ptr; + *aes_buf_len = ntohl (*len); + ptr += 4; + *aes_buf = GNUNET_malloc (*aes_buf_len); + memcpy(*aes_buf, ptr, *aes_buf_len); + ptr += *aes_buf_len; + len = (uint32_t*)ptr; + *cph_buf_len = ntohl (*len); + ptr += 4; + *cph_buf = GNUNET_malloc (*cph_buf_len); + memcpy(*cph_buf, ptr, *cph_buf_len); + + return buf_len; +} + +/** + * @ingroup abe + * Encrypt a block using sessionkey. + * + * @param block the block to encrypt + * @param size the size of the @a block + * @param policy the ABE policy + * @param key the key used to encrypt + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_encrypt (const void *block, + size_t size, + const char *policy, + const struct GNUNET_ABE_AbeMasterKey *key, + void **result) +{ + gabe_cph_t* cph; + char* plt; + char* cph_buf; + char* aes_buf; + element_t m; + int cph_buf_len; + int aes_buf_len; + ssize_t result_len; + + if( !(cph = gabe_enc(key->pub, m, (char*)policy)) ) + return GNUNET_SYSERR; + cph_buf_len = gabe_cph_serialize(cph, + &cph_buf); + gabe_cph_free(cph); + GNUNET_free (cph); + plt = GNUNET_memdup (block, size); + aes_buf_len = aes_128_cbc_encrypt(plt, size, m, &aes_buf); + GNUNET_free (plt); + element_clear(m); + result_len = write_cpabe(result, size, cph_buf, cph_buf_len, aes_buf, aes_buf_len); + GNUNET_free(cph_buf); + GNUNET_free(aes_buf); + return result_len; +} + +/** + * @ingroup abe + * Decrypt a block using the ABE key. + * + * @param block the block to encrypt + * @param size the size of the @a block + * @param key the key used to decrypt + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_decrypt (const void *block, + size_t size, + const struct GNUNET_ABE_AbeKey *key, + void **result) +{ + char* aes_buf; + char* cph_buf; + gabe_cph_t* cph; + element_t m; + int cph_buf_size; + int aes_buf_size; + int plt_len; + + read_cpabe(block, &cph_buf, &cph_buf_size, &aes_buf, &aes_buf_size); + cph = gabe_cph_unserialize(key->pub, cph_buf, cph_buf_size); + if( !gabe_dec(key->pub, key->prv, cph, m) ) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s\n", gabe_error()); + GNUNET_free (aes_buf); + GNUNET_free (cph_buf); + gabe_cph_free(cph); + GNUNET_free (cph); + element_clear (m); + return GNUNET_SYSERR; + } + gabe_cph_free(cph); + GNUNET_free (cph); + plt_len = aes_128_cbc_decrypt(aes_buf, aes_buf_size, m, (char**)result); + GNUNET_free (cph_buf); + GNUNET_free (aes_buf); + element_clear (m); + //freeing is buggy in gabe + //gabe_prv_free (prv); + //gabe_pub_free (pub); + return plt_len; +} + +/** + * @ingroup abe + * Serialize an ABE key. + * + * @param key the key to serialize + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_serialize_key (const struct GNUNET_ABE_AbeKey *key, + void **result) +{ + ssize_t len; + char *pub; + char *prv; + int pub_len; + int prv_len; + + pub_len = gabe_pub_serialize (key->pub, &pub); + prv_len = gabe_prv_serialize (key->prv, &prv); + + len = pub_len + prv_len + 12; + write_cpabe (result, len, pub, pub_len, prv, prv_len); + + GNUNET_free (pub); + GNUNET_free (prv); + + return len; +} + +/** + * @ingroup abe + * Deserialize a serialized ABE key. + * + * @param data the data to deserialize + * @param len the length of the data. + * @return the ABE key. NULL of unsuccessful + */ +struct GNUNET_ABE_AbeKey* +GNUNET_ABE_cpabe_deserialize_key (const void *data, + size_t len) +{ + struct GNUNET_ABE_AbeKey *key; + char *pub; + char *prv; + int prv_len; + int pub_len; + + key = GNUNET_new (struct GNUNET_ABE_AbeKey); + read_cpabe (data, + &pub, + &pub_len, + &prv, + &prv_len); + key->pub = gabe_pub_unserialize (pub, pub_len); + key->prv = gabe_prv_unserialize (key->pub, prv, prv_len); + + GNUNET_free (pub); + GNUNET_free (prv); + return key; +} + +/** + * @ingroup abe + * Serialize an ABE master key. + * + * @param key the key to serialize + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_serialize_master_key (const struct GNUNET_ABE_AbeMasterKey *key, + void **result) +{ + ssize_t len; + char *pub; + char *msk; + int pub_len; + int msk_len; + + pub_len = gabe_pub_serialize (key->pub, &pub); + msk_len = gabe_msk_serialize (key->msk, &msk); + + len = pub_len + msk_len + 12; + write_cpabe (result, len, pub, pub_len, msk, msk_len); + + GNUNET_free (pub); + GNUNET_free (msk); + + return len; +} + +/** + * @ingroup abe + * Deserialize an ABE master key. + * + * @param data the data to deserialize + * @param len the length of the data. + * @return the ABE key. NULL of unsuccessful + */ +struct GNUNET_ABE_AbeMasterKey* +GNUNET_ABE_cpabe_deserialize_master_key (const void *data, + size_t len) +{ + struct GNUNET_ABE_AbeMasterKey *key; + char *msk; + char *pub; + int msk_len; + int pub_len; + + key = GNUNET_new (struct GNUNET_ABE_AbeMasterKey); + read_cpabe (data, + &pub, + &pub_len, + &msk, + &msk_len); + key->pub = gabe_pub_unserialize (pub, pub_len); + key->msk = gabe_msk_unserialize (key->pub, msk, msk_len); + + GNUNET_free (pub); + GNUNET_free (msk); + + return key; +} diff --git a/src/abe/test_cpabe.c b/src/abe/test_cpabe.c new file mode 100644 index 000000000..9b2062b23 --- /dev/null +++ b/src/abe/test_cpabe.c @@ -0,0 +1,87 @@ +/* + This file is part of GNUnet. + Copyright (C) 2002, 2003, 2004, 2006 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ +/** + * @author Martin Schanzenbach + * @file util/test_crypto_abe.c + * @brief test for ABE ciphers + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_abe_lib.h" + +#define TESTSTRING "Hello World!" + +static int +testAbecipher () +{ + struct GNUNET_ABE_AbeMasterKey *msk; + struct GNUNET_ABE_AbeKey *key; + char *result; + char **attrs; + int size; + char *res; + msk = GNUNET_ABE_cpabe_create_master_key (); + size = GNUNET_ABE_cpabe_encrypt (TESTSTRING, strlen (TESTSTRING) + 1, + "testattr", //Policy + msk, + (void*)&result); + GNUNET_assert (-1 != size); + attrs = GNUNET_malloc (2 * sizeof (char*)); + attrs[0] = "testattr"; + attrs[1] = NULL; + key = GNUNET_ABE_cpabe_create_key (msk, + attrs); + + size = GNUNET_ABE_cpabe_decrypt (result, size, + key, + (void*)&res); + if (strlen (TESTSTRING) + 1 != size) + { + printf ("abeciphertest failed: decryptBlock returned %d\n", size); + return 1; + } + if (0 != strcmp (res, TESTSTRING)) + { + printf ("abeciphertest failed: %s != %s\n", res, TESTSTRING); + return 1; + } + else + return 0; +} + + +int +main (int argc, char *argv[]) +{ + int failureCount = 0; + + GNUNET_log_setup ("test-crypto-abe", "WARNING", NULL); + failureCount += testAbecipher (); + + if (failureCount != 0) + { + printf ("%d TESTS FAILED!\n", failureCount); + return -1; + } + return 0; +} + +/* end of test_crypto_aes.c */ diff --git a/src/credential/Makefile.am b/src/credential/Makefile.am new file mode 100644 index 000000000..ca11c5e4f --- /dev/null +++ b/src/credential/Makefile.am @@ -0,0 +1,112 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +EXTRA_DIST = \ + test_credential_defaults.conf \ + test_credential_lookup.conf + + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 +endif + +pkgcfgdir = $(pkgdatadir)/config.d/ + +libexecdir= $(pkglibdir)/libexec/ + +plugindir = $(libdir)/gnunet + +pkgcfg_DATA = \ + credential.conf + + +# /usr/lib - compiles a layer which can be used to be communicagte with the service +lib_LTLIBRARIES = \ + libgnunetcredential.la + +# /usr/lib/gnunet/libexec - Business logic . Separate process +libexec_PROGRAMS = \ + gnunet-service-credential + +bin_PROGRAMS = \ + gnunet-credential + +plugin_LTLIBRARIES = \ + libgnunet_plugin_gnsrecord_credential.la + + +if HAVE_MHD +if HAVE_JSON +plugin_LTLIBRARIES += libgnunet_plugin_rest_credential.la +endif +endif + + +gnunet_credential_SOURCES = \ + gnunet-credential.c +gnunet_credential_LDADD = \ + libgnunetcredential.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(GN_LIBINTL) + + +libgnunet_plugin_gnsrecord_credential_la_SOURCES = \ + plugin_gnsrecord_credential.c +libgnunet_plugin_gnsrecord_credential_la_LIBADD = \ + libgnunetcredential.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LTLIBINTL) +libgnunet_plugin_gnsrecord_credential_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + + +gnunet_service_credential_SOURCES = \ + gnunet-service-credential.c +gnunet_service_credential_LDADD = \ + libgnunetcredential.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/gns/libgnunetgns.la \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(GN_LIBINTL) + + +libgnunetcredential_la_SOURCES = \ + credential_api.c \ + credential_serialization.c \ + credential_misc.c +libgnunetcredential_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIB) +libgnunetcredential_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) + + +libgnunet_plugin_rest_credential_la_SOURCES = \ + plugin_rest_credential.c +libgnunet_plugin_rest_credential_la_LIBADD = \ + libgnunetcredential.la \ + $(top_builddir)/src/rest/libgnunetrest.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ + $(top_builddir)/src/jsonapi/libgnunetjsonapiutils.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ + $(LTLIBINTL) -ljansson -lmicrohttpd +libgnunet_plugin_rest_credential_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + +check_SCRIPTS = \ + test_credential_issue.sh \ + test_credential_verify_simple.sh \ + test_credential_verify.sh \ + test_credential_verify_and.sh + +if ENABLE_TEST_RUN +if HAVE_SQLITE + AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; + TESTS = $(check_SCRIPTS) +endif +endif diff --git a/src/credential/credential.conf.in b/src/credential/credential.conf.in new file mode 100644 index 000000000..71f3066ca --- /dev/null +++ b/src/credential/credential.conf.in @@ -0,0 +1,5 @@ +[credential] +BINARY = gnunet-service-credential +UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-credential.sock +USER_SERVICE = YES +OPTIONS = -L DEBUG
\ No newline at end of file diff --git a/src/credential/credential.h b/src/credential/credential.h new file mode 100644 index 000000000..66a4636fc --- /dev/null +++ b/src/credential/credential.h @@ -0,0 +1,221 @@ +/* + This file is part of GNUnet + Copyright (C) 2012-2013 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/** + * @file credential/credential.h + * @brief IPC messages between CREDENTIAL API and CREDENTIAL service + * @author Martin Schanzenbach + */ +#ifndef CREDENTIAL_H +#define CREDENTIAL_H + +#include "gnunet_credential_service.h" + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message from client to Credential service to collect credentials. + */ +struct CollectMessage +{ + /** + * Header of type #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY + */ + struct GNUNET_MessageHeader header; + + /** + * Subject public key + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey subject_key; + + /** + * Trust anchor + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Length of the issuer attribute + */ + uint16_t issuer_attribute_len; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /* Followed by the zero-terminated attribute */ + +}; + + +/** + * Message from client to Credential service to verify attributes. + */ +struct VerifyMessage +{ + /** + * Header of type #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY + */ + struct GNUNET_MessageHeader header; + + /** + * Subject public key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Trust anchor + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Number of credentials + */ + uint32_t c_count; + + /** + * Length of the issuer attribute + */ + uint16_t issuer_attribute_len; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /* Followed by the zero-terminated attribute and credentials to look up */ + +}; + + +/** + * Message from CREDENTIAL service to client: new results. + */ +struct DelegationChainResultMessage +{ + /** + * Header of type #GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Indicates if credential has been found at all + */ + uint32_t cred_found GNUNET_PACKED; + + /** + * The number of delegations in the response + */ + uint32_t d_count GNUNET_PACKED; + + /** + * The number of credentials in the response + */ + uint32_t c_count GNUNET_PACKED; + + /* followed by ad_count GNUNET_CREDENTIAL_RecordData structs*/ + +}; + +struct DelegationRecordData +{ + /** + * Subject key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Subject attributes + */ + uint32_t subject_attribute_len GNUNET_PACKED; +}; + + +struct ChainEntry +{ + /** + * Issuer key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Subject key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Issuer attributes + */ + uint32_t issuer_attribute_len GNUNET_PACKED; + + /** + * Subject attributes + */ + uint32_t subject_attribute_len GNUNET_PACKED; +}; + + +struct CredentialEntry +{ + + /** + * The signature for this credential by the issuer + */ + struct GNUNET_CRYPTO_EcdsaSignature signature; + + /** + * Signature meta + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Public key of the issuer + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Public key of the subject this credential was issued to + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Expiration time of this credential + */ + uint64_t expiration GNUNET_PACKED; + + /** + * Issuer attribute length + */ + uint32_t issuer_attribute_len; + + /** + * Followed by the attribute string + */ +}; + + +GNUNET_NETWORK_STRUCT_END + +#endif + diff --git a/src/credential/credential_api.c b/src/credential/credential_api.c new file mode 100644 index 000000000..677cb9ad4 --- /dev/null +++ b/src/credential/credential_api.c @@ -0,0 +1,511 @@ +/* + This file is part of GNUnet. + Copyright (C) 2009-2013, 2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/** + * @file credential/credential_api.c + * @brief library to access the CREDENTIAL service + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" +#include "credential.h" +#include "credential_serialization.h" +#include "gnunet_credential_service.h" +#include "gnunet_identity_service.h" + + +#define LOG(kind,...) GNUNET_log_from (kind, "credential-api",__VA_ARGS__) + +/** + * Handle to a verify request + */ +struct GNUNET_CREDENTIAL_Request +{ + + /** + * DLL + */ + struct GNUNET_CREDENTIAL_Request *next; + + /** + * DLL + */ + struct GNUNET_CREDENTIAL_Request *prev; + + /** + * handle to credential service + */ + struct GNUNET_CREDENTIAL_Handle *credential_handle; + + /** + * processor to call on verify result + */ + GNUNET_CREDENTIAL_CredentialResultProcessor verify_proc; + + /** + * @e verify_proc closure + */ + void *proc_cls; + + /** + * Envelope with the message for this queue entry. + */ + struct GNUNET_MQ_Envelope *env; + + /** + * request id + */ + uint32_t r_id; + +}; + + +/** + * Connection to the CREDENTIAL service. + */ +struct GNUNET_CREDENTIAL_Handle +{ + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Connection to service (if available). + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Head of linked list of active verify requests. + */ + struct GNUNET_CREDENTIAL_Request *request_head; + + /** + * Tail of linked list of active verify requests. + */ + struct GNUNET_CREDENTIAL_Request *request_tail; + + /** + * Reconnect task + */ + struct GNUNET_SCHEDULER_Task *reconnect_task; + + /** + * How long do we wait until we try to reconnect? + */ + struct GNUNET_TIME_Relative reconnect_backoff; + + /** + * Request Id generator. Incremented by one for each request. + */ + uint32_t r_id_gen; + +}; + + +/** + * Reconnect to CREDENTIAL service. + * + * @param handle the handle to the CREDENTIAL service + */ +static void +reconnect (struct GNUNET_CREDENTIAL_Handle *handle); + + +/** + * Reconnect to CREDENTIAL + * + * @param cls the handle + */ +static void +reconnect_task (void *cls) +{ + struct GNUNET_CREDENTIAL_Handle *handle = cls; + + handle->reconnect_task = NULL; + reconnect (handle); +} + + +/** + * Disconnect from service and then reconnect. + * + * @param handle our handle + */ +static void +force_reconnect (struct GNUNET_CREDENTIAL_Handle *handle) +{ + GNUNET_MQ_destroy (handle->mq); + handle->mq = NULL; + handle->reconnect_backoff + = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff); + handle->reconnect_task + = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff, + &reconnect_task, + handle); +} + + +/** + * Generic error handler, called with the appropriate error code and + * the same closure specified at the creation of the message queue. + * Not every message queue implementation supports an error handler. + * + * @param cls closure with the `struct GNUNET_CREDENTIAL_Handle *` + * @param error error code + */ +static void +mq_error_handler (void *cls, + enum GNUNET_MQ_Error error) +{ + struct GNUNET_CREDENTIAL_Handle *handle = cls; + + force_reconnect (handle); +} + +/** + * Check validity of message received from the CREDENTIAL service + * + * @param cls the `struct GNUNET_CREDENTIAL_Handle *` + * @param vr_msg the incoming message + */ +static int +check_result (void *cls, + const struct DelegationChainResultMessage *vr_msg) +{ + //TODO + return GNUNET_OK; +} + + +/** + * Handler for messages received from the CREDENTIAL service + * + * @param cls the `struct GNUNET_CREDENTIAL_Handle *` + * @param vr_msg the incoming message + */ +static void +handle_result (void *cls, + const struct DelegationChainResultMessage *vr_msg) +{ + struct GNUNET_CREDENTIAL_Handle *handle = cls; + uint32_t r_id = ntohl (vr_msg->id); + struct GNUNET_CREDENTIAL_Request *vr; + size_t mlen = ntohs (vr_msg->header.size) - sizeof (*vr_msg); + uint32_t d_count = ntohl (vr_msg->d_count); + uint32_t c_count = ntohl (vr_msg->c_count); + struct GNUNET_CREDENTIAL_Delegation d_chain[d_count]; + struct GNUNET_CREDENTIAL_Credential creds[c_count]; + GNUNET_CREDENTIAL_CredentialResultProcessor proc; + void *proc_cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received verify reply from CREDENTIAL service\n"); + for (vr = handle->request_head; NULL != vr; vr = vr->next) + if (vr->r_id == r_id) + break; + if (NULL == vr) + return; + proc = vr->verify_proc; + proc_cls = vr->proc_cls; + GNUNET_CONTAINER_DLL_remove (handle->request_head, + handle->request_tail, + vr); + GNUNET_MQ_discard (vr->env); + GNUNET_free (vr); + GNUNET_assert (GNUNET_OK == + GNUNET_CREDENTIAL_delegation_chain_deserialize (mlen, + (const char*) &vr_msg[1], + d_count, + d_chain, + c_count, + creds)); + if (GNUNET_NO == ntohl (vr_msg->cred_found)) + { + proc (proc_cls, + 0, + NULL, + 0, + NULL); // TODO + } else { + proc (proc_cls, + d_count, + d_chain, + c_count, + creds); + } +} + + +/** + * Reconnect to CREDENTIAL service. + * + * @param handle the handle to the CREDENTIAL service + */ +static void +reconnect (struct GNUNET_CREDENTIAL_Handle *handle) +{ + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_var_size (result, + GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT, + struct DelegationChainResultMessage, + handle), + GNUNET_MQ_hd_var_size (result, + GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT_RESULT, + struct DelegationChainResultMessage, + handle), + GNUNET_MQ_handler_end () + }; + struct GNUNET_CREDENTIAL_Request *vr; + + GNUNET_assert (NULL == handle->mq); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Trying to connect to CREDENTIAL\n"); + handle->mq = GNUNET_CLIENT_connect (handle->cfg, + "credential", + handlers, + &mq_error_handler, + handle); + if (NULL == handle->mq) + return; + for (vr = handle->request_head; NULL != vr; vr = vr->next) + GNUNET_MQ_send_copy (handle->mq, + vr->env); +} + + +/** + * Initialize the connection with the CREDENTIAL service. + * + * @param cfg configuration to use + * @return handle to the CREDENTIAL service, or NULL on error + */ +struct GNUNET_CREDENTIAL_Handle * +GNUNET_CREDENTIAL_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + struct GNUNET_CREDENTIAL_Handle *handle; + + handle = GNUNET_new (struct GNUNET_CREDENTIAL_Handle); + handle->cfg = cfg; + reconnect (handle); + if (NULL == handle->mq) + { + GNUNET_free (handle); + return NULL; + } + return handle; +} + + +/** + * Shutdown connection with the CREDENTIAL service. + * + * @param handle handle of the CREDENTIAL connection to stop + */ +void +GNUNET_CREDENTIAL_disconnect (struct GNUNET_CREDENTIAL_Handle *handle) +{ + if (NULL != handle->mq) + { + GNUNET_MQ_destroy (handle->mq); + handle->mq = NULL; + } + if (NULL != handle->reconnect_task) + { + GNUNET_SCHEDULER_cancel (handle->reconnect_task); + handle->reconnect_task = NULL; + } + GNUNET_assert (NULL == handle->request_head); + GNUNET_free (handle); +} + + +/** + * Cancel pending verify request + * + * @param lr the verify request to cancel + */ +void +GNUNET_CREDENTIAL_request_cancel (struct GNUNET_CREDENTIAL_Request *lr) +{ + struct GNUNET_CREDENTIAL_Handle *handle = lr->credential_handle; + + GNUNET_CONTAINER_DLL_remove (handle->request_head, + handle->request_tail, + lr); + GNUNET_MQ_discard (lr->env); + GNUNET_free (lr); +} + + +/** + * Performs attribute collection. + * Collects all credentials of subject to fulfill the + * attribute, if possible + * + * @param handle handle to the Credential service + * @param issuer_key the issuer public key + * @param issuer_attribute the issuer attribute + * @param subject_key the subject public key + * @param proc function to call on result + * @param proc_cls closure for processor + * @return handle to the queued request + */ +struct GNUNET_CREDENTIAL_Request* +GNUNET_CREDENTIAL_collect (struct GNUNET_CREDENTIAL_Handle *handle, + const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key, + const char *issuer_attribute, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *subject_key, + GNUNET_CREDENTIAL_CredentialResultProcessor proc, + void *proc_cls) +{ + /* IPC to shorten credential names, return shorten_handle */ + struct CollectMessage *c_msg; + struct GNUNET_CREDENTIAL_Request *vr; + size_t nlen; + + if (NULL == issuer_attribute) + { + GNUNET_break (0); + return NULL; + } + + //DEBUG LOG + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Trying to collect `%s' in CREDENTIAL\n", + issuer_attribute); + nlen = strlen (issuer_attribute) + 1; + if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*vr)) + { + GNUNET_break (0); + return NULL; + } + vr = GNUNET_new (struct GNUNET_CREDENTIAL_Request); + vr->credential_handle = handle; + vr->verify_proc = proc; + vr->proc_cls = proc_cls; + vr->r_id = handle->r_id_gen++; + vr->env = GNUNET_MQ_msg_extra (c_msg, + nlen, + GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT); + c_msg->id = htonl (vr->r_id); + c_msg->subject_key = *subject_key; + c_msg->issuer_key = *issuer_key; + c_msg->issuer_attribute_len = htons(strlen(issuer_attribute)); + GNUNET_memcpy (&c_msg[1], + issuer_attribute, + strlen (issuer_attribute)); + GNUNET_CONTAINER_DLL_insert (handle->request_head, + handle->request_tail, + vr); + if (NULL != handle->mq) + GNUNET_MQ_send_copy (handle->mq, + vr->env); + return vr; +} +/** + * Performs attribute verification. + * Checks if there is a delegation chain from + * attribute ``issuer_attribute'' issued by the issuer + * with public key ``issuer_key'' maps to the attribute + * ``subject_attribute'' claimed by the subject with key + * ``subject_key'' + * + * @param handle handle to the Credential service + * @param issuer_key the issuer public key + * @param issuer_attribute the issuer attribute + * @param subject_key the subject public key + * @param credential_count number of credentials provided + * @param credentials subject credentials + * @param proc function to call on result + * @param proc_cls closure for processor + * @return handle to the queued request + */ +struct GNUNET_CREDENTIAL_Request* +GNUNET_CREDENTIAL_verify (struct GNUNET_CREDENTIAL_Handle *handle, + const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key, + const char *issuer_attribute, + const struct GNUNET_CRYPTO_EcdsaPublicKey *subject_key, + uint32_t credential_count, + const struct GNUNET_CREDENTIAL_Credential *credentials, + GNUNET_CREDENTIAL_CredentialResultProcessor proc, + void *proc_cls) +{ + /* IPC to shorten credential names, return shorten_handle */ + struct VerifyMessage *v_msg; + struct GNUNET_CREDENTIAL_Request *vr; + size_t nlen; + size_t clen; + + if (NULL == issuer_attribute || NULL == credentials) + { + GNUNET_break (0); + return NULL; + } + + clen = GNUNET_CREDENTIAL_credentials_get_size (credential_count, + credentials); + + //DEBUG LOG + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Trying to verify `%s' in CREDENTIAL\n", + issuer_attribute); + nlen = strlen (issuer_attribute) + 1 + clen; + if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*vr)) + { + GNUNET_break (0); + return NULL; + } + vr = GNUNET_new (struct GNUNET_CREDENTIAL_Request); + vr->credential_handle = handle; + vr->verify_proc = proc; + vr->proc_cls = proc_cls; + vr->r_id = handle->r_id_gen++; + vr->env = GNUNET_MQ_msg_extra (v_msg, + nlen, + GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY); + v_msg->id = htonl (vr->r_id); + v_msg->subject_key = *subject_key; + v_msg->c_count = htonl(credential_count); + v_msg->issuer_key = *issuer_key; + v_msg->issuer_attribute_len = htons(strlen(issuer_attribute)); + GNUNET_memcpy (&v_msg[1], + issuer_attribute, + strlen (issuer_attribute)); + GNUNET_CREDENTIAL_credentials_serialize (credential_count, + credentials, + clen, + ((char*)&v_msg[1]) + + strlen (issuer_attribute) + 1); + GNUNET_CONTAINER_DLL_insert (handle->request_head, + handle->request_tail, + vr); + if (NULL != handle->mq) + GNUNET_MQ_send_copy (handle->mq, + vr->env); + return vr; +} + +/* end of credential_api.c */ diff --git a/src/credential/credential_misc.c b/src/credential/credential_misc.c new file mode 100644 index 000000000..c94c33919 --- /dev/null +++ b/src/credential/credential_misc.c @@ -0,0 +1,168 @@ +/* + This file is part of GNUnet. + Copyright (C) 2009-2013, 2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +/** + * @file credential/credential_misc.c + * @brief Misc API for credentials + * + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_credential_service.h" +#include "gnunet_signatures.h" +#include "credential.h" +#include <inttypes.h> + +char* +GNUNET_CREDENTIAL_credential_to_string (const struct GNUNET_CREDENTIAL_Credential *cred) +{ + char *cred_str; + char *subject_pkey; + char *issuer_pkey; + char *signature; + + + subject_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key); + issuer_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key); + GNUNET_STRINGS_base64_encode ((char*)&cred->signature, + sizeof (struct GNUNET_CRYPTO_EcdsaSignature), + &signature); + GNUNET_asprintf (&cred_str, + "%s.%s -> %s | %s | %"SCNu64, + issuer_pkey, + cred->issuer_attribute, + subject_pkey, + signature, + cred->expiration.abs_value_us); + GNUNET_free (subject_pkey); + GNUNET_free (issuer_pkey); + GNUNET_free (signature); + return cred_str; +} + +struct GNUNET_CREDENTIAL_Credential* +GNUNET_CREDENTIAL_credential_from_string (const char* s) +{ + struct GNUNET_CREDENTIAL_Credential *cred; + size_t enclen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8; + if (enclen % 5 > 0) + enclen += 5 - enclen % 5; + enclen /= 5; /* 260/5 = 52 */ + char subject_pkey[enclen + 1]; + char issuer_pkey[enclen + 1]; + char name[253 + 1]; + char signature[256]; //TODO max payload size + + struct GNUNET_CRYPTO_EcdsaSignature *sig; + struct GNUNET_TIME_Absolute etime_abs; + + if (5 != SSCANF (s, + "%52s.%253s -> %52s | %s | %"SCNu64, + issuer_pkey, + name, + subject_pkey, + signature, + &etime_abs.abs_value_us)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to parse CRED record string `%s'\n"), + s); + return NULL; + } + cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + strlen (name) + 1); + GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey, + strlen (subject_pkey), + &cred->subject_key); + GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_pkey, + strlen (issuer_pkey), + &cred->issuer_key); + GNUNET_assert (sizeof (struct GNUNET_CRYPTO_EcdsaSignature) == GNUNET_STRINGS_base64_decode (signature, + strlen (signature), + (char**)&sig)); + cred->signature = *sig; + cred->expiration = etime_abs; + GNUNET_free (sig); + GNUNET_memcpy (&cred[1], + name, + strlen (name)+1); + cred->issuer_attribute_len = strlen ((char*)&cred[1]); + cred->issuer_attribute = (char*)&cred[1]; + return cred; +} + +/** + * Issue an attribute to a subject + * + * @param issuer the ego that should be used to issue the attribute + * @param subject the subject of the attribute + * @param attribute the name of the attribute + * @return handle to the queued request + */ +struct GNUNET_CREDENTIAL_Credential * +GNUNET_CREDENTIAL_credential_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer, + struct GNUNET_CRYPTO_EcdsaPublicKey *subject, + const char *attribute, + struct GNUNET_TIME_Absolute *expiration) +{ + struct CredentialEntry *crd; + struct GNUNET_CREDENTIAL_Credential *cred; + size_t size; + + size = sizeof (struct CredentialEntry) + strlen (attribute) + 1; + crd = GNUNET_malloc (size); + cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + strlen (attribute) + 1); + crd->purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); + + crd->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL); + GNUNET_CRYPTO_ecdsa_key_get_public (issuer, + &crd->issuer_key); + crd->subject_key = *subject; + crd->expiration = GNUNET_htonll (expiration->abs_value_us); + crd->issuer_attribute_len = htonl (strlen (attribute)+1); + GNUNET_memcpy ((char*)&crd[1], + attribute, + strlen (attribute)+1); + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_sign (issuer, + &crd->purpose, + &crd->signature)) + { + GNUNET_break (0); + GNUNET_free (crd); + return NULL; + } + cred->signature = crd->signature; + cred->expiration = *expiration; + GNUNET_CRYPTO_ecdsa_key_get_public (issuer, + &cred->issuer_key); + + cred->subject_key = *subject; + GNUNET_memcpy (&cred[1], + attribute, + strlen (attribute)+1); + cred->issuer_attribute = (char*)&cred[1]; + GNUNET_free (crd); + return cred; +} + + diff --git a/src/credential/credential_misc.h b/src/credential/credential_misc.h new file mode 100644 index 000000000..c3aa8c214 --- /dev/null +++ b/src/credential/credential_misc.h @@ -0,0 +1,35 @@ +/* + This file is part of GNUnet + Copyright (C) 2012-2013 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/** + * @file credential/credential_misc.h + * @brief Credential helper functions + */ +#ifndef CREDENTIAL_MISC_H +#define CREDENTIAL_MISC_H + + + +char* +GNUNET_CREDENTIAL_credential_to_string (const struct GNUNET_CREDENTIAL_Credential *cred); + +struct GNUNET_CREDENTIAL_Credential* +GNUNET_CREDENTIAL_credential_from_string (const char* str); + +#endif diff --git a/src/credential/credential_serialization.c b/src/credential/credential_serialization.c new file mode 100644 index 000000000..1d23bb08c --- /dev/null +++ b/src/credential/credential_serialization.c @@ -0,0 +1,460 @@ +/* + This file is part of GNUnet. + Copyright (C) 2009-2013, 2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +/** + * @file credential/credential_serialization.c + * @brief API to serialize and deserialize delegation chains + * and credentials + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_credential_service.h" +#include "gnunet_signatures.h" +#include "credential.h" + +/** + * Calculate how many bytes we will need to serialize + * the given delegation chain + * + * @param ds_count number of delegation chain entries + * @param dsr array of #GNUNET_CREDENTIAL_DelegationSet + * @return the required size to serialize + */ +size_t +GNUNET_CREDENTIAL_delegation_set_get_size (unsigned int ds_count, + const struct GNUNET_CREDENTIAL_DelegationSet *dsr) +{ + unsigned int i; + size_t ret; + + ret = sizeof (struct DelegationRecordData) * (ds_count); + + for (i=0; i<ds_count;i++) + { + GNUNET_assert ((ret + dsr[i].subject_attribute_len) >= ret); + ret += dsr[i].subject_attribute_len; + } + return ret; +} + +/** + * Serizalize the given delegation chain entries and credential + * + * @param d_count number of delegation chain entries + * @param dsr array of #GNUNET_CREDENTIAL_DelegationSet + * @param dest_size size of the destination + * @param dest where to store the result + * @return the size of the data, -1 on failure + */ +ssize_t +GNUNET_CREDENTIAL_delegation_set_serialize (unsigned int d_count, + const struct GNUNET_CREDENTIAL_DelegationSet *dsr, + size_t dest_size, + char *dest) +{ + struct DelegationRecordData rec; + unsigned int i; + size_t off; + + off = 0; + for (i=0;i<d_count;i++) + { + rec.subject_attribute_len = htonl ((uint32_t) dsr[i].subject_attribute_len); + rec.subject_key = dsr[i].subject_key; + if (off + sizeof (rec) > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + &rec, + sizeof (rec)); + off += sizeof (rec); + if (0 == dsr[i].subject_attribute_len) + continue; + if (off + dsr[i].subject_attribute_len > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + dsr[i].subject_attribute, + dsr[i].subject_attribute_len); + off += dsr[i].subject_attribute_len; + } + return off; +} + + +/** + * Deserialize the given destination + * + * @param len size of the serialized delegation chain and cred + * @param src the serialized data + * @param d_count the number of delegation chain entries + * @param dsr where to put the delegation chain entries + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +GNUNET_CREDENTIAL_delegation_set_deserialize (size_t len, + const char *src, + unsigned int d_count, + struct GNUNET_CREDENTIAL_DelegationSet *dsr) +{ + struct DelegationRecordData rec; + unsigned int i; + size_t off; + + off = 0; + for (i=0;i<d_count;i++) + { + if (off + sizeof (rec) > len) + return GNUNET_SYSERR; + GNUNET_memcpy (&rec, &src[off], sizeof (rec)); + dsr[i].subject_key = rec.subject_key; + off += sizeof (rec); + dsr[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len); + if (off + dsr[i].subject_attribute_len > len) + return GNUNET_SYSERR; + dsr[i].subject_attribute = (char*)&src[off]; + off += dsr[i].subject_attribute_len; + } + return GNUNET_OK; +} + + +/** + * Calculate how many bytes we will need to serialize + * the credentials + * + * @param c_count number of credential entries + * @param cd a #GNUNET_CREDENTIAL_Credential + * @return the required size to serialize + */ +size_t +GNUNET_CREDENTIAL_credentials_get_size (unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd) +{ + unsigned int i; + size_t ret; + + ret = sizeof (struct CredentialEntry) * (c_count); + + for (i=0; i<c_count;i++) + { + GNUNET_assert ((ret + cd[i].issuer_attribute_len) >= ret); + ret += cd[i].issuer_attribute_len; + } + return ret; +} +/** + * Serizalize the given credentials + * + * @param c_count number of credential entries + * @param cd a #GNUNET_CREDENTIAL_Credential + * @param dest_size size of the destination + * @param dest where to store the result + * @return the size of the data, -1 on failure + */ +ssize_t +GNUNET_CREDENTIAL_credentials_serialize (unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd, + size_t dest_size, + char *dest) +{ + struct CredentialEntry c_rec; + unsigned int i; + size_t off; + + off = 0; + for (i=0;i<c_count;i++) + { + c_rec.issuer_attribute_len = htonl ((uint32_t) cd[i].issuer_attribute_len); + c_rec.issuer_key = cd[i].issuer_key; + c_rec.subject_key = cd[i].subject_key; + c_rec.signature = cd[i].signature; + c_rec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL); + c_rec.purpose.size = htonl ((sizeof (struct CredentialEntry) + cd[i].issuer_attribute_len) - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); + c_rec.expiration = GNUNET_htonll (cd[i].expiration.abs_value_us); + if (off + sizeof (c_rec) > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + &c_rec, + sizeof (c_rec)); + off += sizeof (c_rec); + if (off + cd[i].issuer_attribute_len > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + cd[i].issuer_attribute, + cd[i].issuer_attribute_len); + off += cd[i].issuer_attribute_len; + } + + return off; +} + + + +/** + * Deserialize the given destination + * + * @param len size of the serialized creds + * @param src the serialized data + * @param c_count the number of credential entries + * @param cd where to put the credential data + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +GNUNET_CREDENTIAL_credentials_deserialize (size_t len, + const char *src, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cd) +{ + struct CredentialEntry c_rec; + unsigned int i; + size_t off; + + off = 0; + for (i=0;i<c_count;i++) + { + if (off + sizeof (c_rec) > len) + return GNUNET_SYSERR; + GNUNET_memcpy (&c_rec, &src[off], sizeof (c_rec)); + cd[i].issuer_attribute_len = ntohl ((uint32_t) c_rec.issuer_attribute_len); + cd[i].issuer_key = c_rec.issuer_key; + cd[i].subject_key = c_rec.subject_key; + cd[i].signature = c_rec.signature; + cd[i].expiration.abs_value_us = GNUNET_ntohll(c_rec.expiration); + off += sizeof (c_rec); + if (off + cd[i].issuer_attribute_len > len) + return GNUNET_SYSERR; + cd[i].issuer_attribute = &src[off]; + off += cd[i].issuer_attribute_len; + } + return GNUNET_OK; +} + + + +/** + * Calculate how many bytes we will need to serialize + * the given delegation chain and credential + * + * @param d_count number of delegation chain entries + * @param dd array of #GNUNET_CREDENTIAL_Delegation + * @param c_count number of credential entries + * @param cd a #GNUNET_CREDENTIAL_Credential + * @return the required size to serialize + */ +size_t +GNUNET_CREDENTIAL_delegation_chain_get_size (unsigned int d_count, + const struct GNUNET_CREDENTIAL_Delegation *dd, + unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd) +{ + unsigned int i; + size_t ret; + + ret = sizeof (struct ChainEntry) * (d_count); + + for (i=0; i<d_count;i++) + { + GNUNET_assert ((ret + + dd[i].issuer_attribute_len + + dd[i].subject_attribute_len) >= ret); + ret += dd[i].issuer_attribute_len + dd[i].subject_attribute_len; + } + return ret+GNUNET_CREDENTIAL_credentials_get_size(c_count, cd); + return ret; +} + +/** + * Serizalize the given delegation chain entries and credential + * + * @param d_count number of delegation chain entries + * @param dd array of #GNUNET_CREDENTIAL_Delegation + * @param c_count number of credential entries + * @param cd a #GNUNET_CREDENTIAL_Credential + * @param dest_size size of the destination + * @param dest where to store the result + * @return the size of the data, -1 on failure + */ +ssize_t +GNUNET_CREDENTIAL_delegation_chain_serialize (unsigned int d_count, + const struct GNUNET_CREDENTIAL_Delegation *dd, + unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd, + size_t dest_size, + char *dest) +{ + struct ChainEntry rec; + unsigned int i; + size_t off; + + off = 0; + for (i=0;i<d_count;i++) + { + rec.issuer_attribute_len = htonl ((uint32_t) dd[i].issuer_attribute_len); + rec.subject_attribute_len = htonl ((uint32_t) dd[i].subject_attribute_len); + rec.issuer_key = dd[i].issuer_key; + rec.subject_key = dd[i].subject_key; + if (off + sizeof (rec) > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + &rec, + sizeof (rec)); + off += sizeof (rec); + if (off + dd[i].issuer_attribute_len > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + dd[i].issuer_attribute, + dd[i].issuer_attribute_len); + off += dd[i].issuer_attribute_len; + if (0 == dd[i].subject_attribute_len) + continue; + if (off + dd[i].subject_attribute_len > dest_size) + return -1; + GNUNET_memcpy (&dest[off], + dd[i].subject_attribute, + dd[i].subject_attribute_len); + off += dd[i].subject_attribute_len; + } + return off+GNUNET_CREDENTIAL_credentials_serialize (c_count, + cd, + dest_size-off, + &dest[off]); +} + + +/** + * Deserialize the given destination + * + * @param len size of the serialized delegation chain and cred + * @param src the serialized data + * @param d_count the number of delegation chain entries + * @param dd where to put the delegation chain entries + * @param c_count the number of credential entries + * @param cd where to put the credential data + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +GNUNET_CREDENTIAL_delegation_chain_deserialize (size_t len, + const char *src, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *dd, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cd) +{ + struct ChainEntry rec; + unsigned int i; + size_t off; + + off = 0; + for (i=0;i<d_count;i++) + { + if (off + sizeof (rec) > len) + return GNUNET_SYSERR; + GNUNET_memcpy (&rec, &src[off], sizeof (rec)); + dd[i].issuer_attribute_len = ntohl ((uint32_t) rec.issuer_attribute_len); + dd[i].issuer_key = rec.issuer_key; + dd[i].subject_key = rec.subject_key; + off += sizeof (rec); + if (off + dd[i].issuer_attribute_len > len) + return GNUNET_SYSERR; + dd[i].issuer_attribute = &src[off]; + off += dd[i].issuer_attribute_len; + dd[i].subject_attribute_len = ntohl ((uint32_t) rec.subject_attribute_len); + if (off + dd[i].subject_attribute_len > len) + return GNUNET_SYSERR; + dd[i].subject_attribute = &src[off]; + off += dd[i].subject_attribute_len; + } + return GNUNET_CREDENTIAL_credentials_deserialize (len-off, + &src[off], + c_count, + cd); +} +int +GNUNET_CREDENTIAL_credential_serialize (struct GNUNET_CREDENTIAL_Credential *cred, + char **data) +{ + size_t size; + struct CredentialEntry *cdata; + + size = sizeof (struct CredentialEntry) + strlen (cred->issuer_attribute) + 1; + *data = GNUNET_malloc (size); + cdata = (struct CredentialEntry*)*data; + cdata->subject_key = cred->subject_key; + cdata->issuer_key = cred->issuer_key; + cdata->expiration = GNUNET_htonll (cred->expiration.abs_value_us); + cdata->signature = cred->signature; + cdata->issuer_attribute_len = htonl (strlen (cred->issuer_attribute) + 1); + cdata->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CREDENTIAL); + cdata->purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); + GNUNET_memcpy (&cdata[1], + cred->issuer_attribute, + strlen (cred->issuer_attribute)); + + if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, + &cdata->purpose, + &cdata->signature, + &cdata->issuer_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid credential\n"); + //return NULL; + } + return size; +} + +struct GNUNET_CREDENTIAL_Credential* +GNUNET_CREDENTIAL_credential_deserialize (const char* data, + size_t data_size) +{ + struct GNUNET_CREDENTIAL_Credential *cred; + struct CredentialEntry *cdata; + char *issuer_attribute; + + if (data_size < sizeof (struct CredentialEntry)) + return NULL; + cdata = (struct CredentialEntry*)data; + if(GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_CREDENTIAL, + &cdata->purpose, + &cdata->signature, + &cdata->issuer_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid credential\n"); + //return NULL; + } + issuer_attribute = (char*)&cdata[1]; + + cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + ntohl(cdata->issuer_attribute_len)); + + cred->issuer_key = cdata->issuer_key; + cred->subject_key = cdata->subject_key; + GNUNET_memcpy (&cred[1], + issuer_attribute, + ntohl (cdata->issuer_attribute_len)); + cred->signature = cdata->signature; + cred->issuer_attribute = (char*)&cred[1]; + cred->expiration.abs_value_us = GNUNET_ntohll (cdata->expiration); + return cred; +} + + +/* end of credential_serialization.c */ diff --git a/src/credential/credential_serialization.h b/src/credential/credential_serialization.h new file mode 100644 index 000000000..b870d47dc --- /dev/null +++ b/src/credential/credential_serialization.h @@ -0,0 +1,159 @@ +/* + This file is part of GNUnet. + Copyright (C) 2009-2013, 2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +/** + * @file credential/credential_serialization.h + * @brief API to serialize and deserialize delegation chains + * and credentials + * @author Martin Schanzenbach + */ +#ifndef CREDENTIAL_SERIALIZATION_H +#define CREDENTIAL_SERIALIZATION_H + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_constants.h" +#include "gnunet_credential_service.h" + +/** + * Calculate how many bytes we will need to serialize + * the given delegation record + * + * @param ds_count number of delegation chain entries + * @param dsr array of #GNUNET_CREDENTIAL_Delegation + * @return the required size to serialize + */ +size_t +GNUNET_CREDENTIAL_delegation_set_get_size (unsigned int ds_count, + const struct GNUNET_CREDENTIAL_DelegationSet *dsr); + +/** + * Serizalize the given delegation record entries + * + * @param d_count number of delegation chain entries + * @param dsr array of #GNUNET_CREDENTIAL_Delegation + * @param dest_size size of the destination + * @param dest where to store the result + * @return the size of the data, -1 on failure + */ +ssize_t +GNUNET_CREDENTIAL_delegation_set_serialize (unsigned int d_count, + const struct GNUNET_CREDENTIAL_DelegationSet *dsr, + size_t dest_size, + char *dest); + + +/** + * Deserialize the given destination + * + * @param len size of the serialized delegation recird + * @param src the serialized data + * @param d_count the number of delegation chain entries + * @param dsr where to put the delegation chain entries + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +GNUNET_CREDENTIAL_delegation_set_deserialize (size_t len, + const char *src, + unsigned int d_count, + struct GNUNET_CREDENTIAL_DelegationSet *dsr); + + /** + * Calculate how many bytes we will need to serialize + * the given delegation chain and credential + * + * @param d_count number of delegation chain entries + * @param dd array of #GNUNET_CREDENTIAL_Delegation + * @param c_count number of credential entries + * @param cd a #GNUNET_CREDENTIAL_Credential + * @return the required size to serialize + */ + size_t + GNUNET_CREDENTIAL_delegation_chain_get_size (unsigned int d_count, + const struct GNUNET_CREDENTIAL_Delegation *dd, + unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd); + + /** + * Serizalize the given delegation chain entries and credential + * + * @param d_count number of delegation chain entries + * @param dd array of #GNUNET_CREDENTIAL_Delegation + * @param c_count number of credential entries + * @param cd a #GNUNET_CREDENTIAL_Credential + * @param dest_size size of the destination + * @param dest where to store the result + * @return the size of the data, -1 on failure + */ + ssize_t + GNUNET_CREDENTIAL_delegation_chain_serialize (unsigned int d_count, + const struct GNUNET_CREDENTIAL_Delegation *dd, + unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd, + size_t dest_size, + char *dest); + + + /** + * Deserialize the given destination + * + * @param len size of the serialized delegation chain and cred + * @param src the serialized data + * @param d_count the number of delegation chain entries + * @param dd where to put the delegation chain entries + * @param c_count number of credential entries + * @param cd where to put the credential data + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ + int + GNUNET_CREDENTIAL_delegation_chain_deserialize (size_t len, + const char *src, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *dd, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cd); + size_t + GNUNET_CREDENTIAL_credentials_get_size (unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd); + +ssize_t +GNUNET_CREDENTIAL_credentials_serialize (unsigned int c_count, + const struct GNUNET_CREDENTIAL_Credential *cd, + size_t dest_size, + char *dest); + + +int +GNUNET_CREDENTIAL_credentials_deserialize (size_t len, + const char *src, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cd); + + +int +GNUNET_CREDENTIAL_credential_serialize (struct GNUNET_CREDENTIAL_Credential *cred, + char **data); + +struct GNUNET_CREDENTIAL_Credential* +GNUNET_CREDENTIAL_credential_deserialize (const char* data, + size_t data_size); +#endif +/* end of credential_serialization.h */ diff --git a/src/credential/gnunet-credential.c b/src/credential/gnunet-credential.c new file mode 100644 index 000000000..03f959b95 --- /dev/null +++ b/src/credential/gnunet-credential.c @@ -0,0 +1,588 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2013 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/** + * @file gnunet-credential.c + * @brief command line tool to access command line Credential service + * @author Martin Schanzenbach + */ +#include "platform.h" +#include <gnunet_util_lib.h> +#include <gnunet_credential_service.h> +#include <gnunet_gnsrecord_lib.h> +#include "credential_misc.h" +#include "credential_serialization.h" + +/** + * Configuration we are using. + */ +static const struct GNUNET_CONFIGURATION_Handle *cfg; + +/** + * EgoLookup + */ +static struct GNUNET_IDENTITY_EgoLookup *el; + +/** + * Handle to Credential service. + */ +static struct GNUNET_CREDENTIAL_Handle *credential; + +/** + * Desired timeout for the lookup (default is no timeout). + */ +static struct GNUNET_TIME_Relative timeout; + +/** + * Handle to verify request + */ +static struct GNUNET_CREDENTIAL_Request *verify_request; + +/** + * Handle to collect request + */ +static struct GNUNET_CREDENTIAL_Request *collect_request; + +/** + * Task scheduled to handle timeout. + */ +static struct GNUNET_SCHEDULER_Task *tt; + +/** + * Subject pubkey string + */ +static char *subject_key; + +/** + * Subject credential string + */ +static char *subject_credential; + +/** + * Credential TTL + */ +static char *expiration; + +/** + * Subject key + */ +struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey; + +/** + * Issuer key + */ +struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey; + + +/** + * Issuer pubkey string + */ +static char *issuer_key; + +/** + * ego + */ +static char *ego_name; + +/** + * Issuer attribute + */ +static char *issuer_attr; + +/** + * Verify mode + */ +static int verify; + +/** + * Issue mode + */ +static int create_cred; + +/** + * Collect mode + */ +static int collect; + +/** + * Task run on shutdown. Cleans up everything. + * + * @param cls unused + */ +static void +do_shutdown (void *cls) +{ + if (NULL != verify_request) + { + GNUNET_CREDENTIAL_request_cancel (verify_request); + verify_request = NULL; + } + if (NULL != credential) + { + GNUNET_CREDENTIAL_disconnect (credential); + credential = NULL; + } + if (NULL != tt) + { + GNUNET_SCHEDULER_cancel (tt); + tt = NULL; + } +} + + +/** + * Task run on timeout. Triggers shutdown. + * + * @param cls unused + */ +static void +do_timeout (void *cls) +{ + tt = NULL; + GNUNET_SCHEDULER_shutdown (); +} + +static void +handle_collect_result (void *cls, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *dc, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cred) +{ + int i; + char* line; + + verify_request = NULL; + if (NULL != cred) + { + for (i=0;i<c_count;i++) + { + line = GNUNET_CREDENTIAL_credential_to_string (&cred[i]); + printf ("%s\n", + line); + GNUNET_free (line); + } + } + + + GNUNET_SCHEDULER_shutdown (); +} + + +static void +handle_verify_result (void *cls, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *dc, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cred) +{ + int i; + char* iss_key; + char* sub_key; + + verify_request = NULL; + if (NULL == cred) + printf ("Failed.\n"); + else + { + printf("Delegation Chain:\n"); + for (i=0;i<d_count;i++) + { + iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].issuer_key); + sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].subject_key); + if (0 != dc[i].subject_attribute_len) + { + printf ("(%d) %s.%s <- %s.%s\n", i, + iss_key, dc[i].issuer_attribute, + sub_key, dc[i].subject_attribute); + } else { + printf ("(%d) %s.%s <- %s\n", i, + iss_key, dc[i].issuer_attribute, + sub_key); + } + GNUNET_free (iss_key); + GNUNET_free (sub_key); + } + printf("\nCredentials:\n"); + for (i=0;i<c_count;i++) + { + iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].issuer_key); + sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred[i].subject_key); + printf ("%s.%s <- %s\n", + iss_key, cred[i].issuer_attribute, + sub_key); + GNUNET_free (iss_key); + GNUNET_free (sub_key); + + } + printf ("Successful.\n"); + } + + + GNUNET_SCHEDULER_shutdown (); +} + +/** + * Callback invoked from identity service with ego information. + * An @a ego of NULL means the ego was not found. + * + * @param cls closure with the configuration + * @param ego an ego known to identity service, or NULL + */ +static void +identity_cb (void *cls, + const struct GNUNET_IDENTITY_Ego *ego) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey; + struct GNUNET_CREDENTIAL_Credential *crd; + struct GNUNET_TIME_Absolute etime_abs; + struct GNUNET_TIME_Relative etime_rel; + char *res; + + el = NULL; + if (NULL == ego) + { + if (NULL != ego_name) + { + fprintf (stderr, + _("Ego `%s' not known to identity service\n"), + ego_name); + } + GNUNET_SCHEDULER_shutdown (); + return; + } + + if (GNUNET_YES == collect) + { + + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key, + strlen (issuer_key), + &issuer_pkey)) + { + fprintf (stderr, + _("Issuer public key `%s' is not well-formed\n"), + issuer_key); + GNUNET_SCHEDULER_shutdown (); + } + privkey = GNUNET_IDENTITY_ego_get_private_key (ego); + + collect_request = GNUNET_CREDENTIAL_collect(credential, + &issuer_pkey, + issuer_attr, //TODO argument + privkey, + &handle_collect_result, + NULL); + return; + } + + //Else issue + + if (NULL == expiration) + { + fprintf (stderr, + "Please specify a TTL\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } else if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration, + &etime_rel)) + { + etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel); + } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration, + &etime_abs)) + { + fprintf (stderr, + "%s is not a valid ttl!\n", + expiration); + GNUNET_SCHEDULER_shutdown (); + return; + } + + + privkey = GNUNET_IDENTITY_ego_get_private_key (ego); + GNUNET_free_non_null (ego_name); + ego_name = NULL; + crd = GNUNET_CREDENTIAL_credential_issue (privkey, + &subject_pkey, + issuer_attr, + &etime_abs); + + res = GNUNET_CREDENTIAL_credential_to_string (crd); + GNUNET_free (crd); + printf ("%s\n", res); + GNUNET_SCHEDULER_shutdown (); +} + + + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param c configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + + cfg = c; + + + tt = GNUNET_SCHEDULER_add_delayed (timeout, + &do_timeout, NULL); + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); + + if (GNUNET_YES == collect) { + if (NULL == issuer_key) + { + fprintf (stderr, + _("Issuer public key not well-formed\n")); + GNUNET_SCHEDULER_shutdown (); + return; + + } + + credential = GNUNET_CREDENTIAL_connect (cfg); + + if (NULL == credential) + { + fprintf (stderr, + _("Failed to connect to CREDENTIAL\n")); + GNUNET_SCHEDULER_shutdown (); + } + if (NULL == issuer_attr) + { + fprintf (stderr, + _("You must provide issuer the attribute\n")); + GNUNET_SCHEDULER_shutdown (); + } + + if (NULL == ego_name) + { + fprintf (stderr, + _("ego required\n")); + GNUNET_SCHEDULER_shutdown (); + return; + + } + el = GNUNET_IDENTITY_ego_lookup (cfg, + ego_name, + &identity_cb, + (void *) cfg); + return; + + } + + if (NULL == subject_key) + { + fprintf (stderr, + _("Subject public key needed\n")); + GNUNET_SCHEDULER_shutdown (); + return; + + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_key, + strlen (subject_key), + &subject_pkey)) + { + fprintf (stderr, + _("Subject public key `%s' is not well-formed\n"), + subject_key); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_YES == verify) { + if (NULL == issuer_key) + { + fprintf (stderr, + _("Issuer public key not well-formed\n")); + GNUNET_SCHEDULER_shutdown (); + return; + + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key, + strlen (issuer_key), + &issuer_pkey)) + { + fprintf (stderr, + _("Issuer public key `%s' is not well-formed\n"), + issuer_key); + GNUNET_SCHEDULER_shutdown (); + } + credential = GNUNET_CREDENTIAL_connect (cfg); + + if (NULL == credential) + { + fprintf (stderr, + _("Failed to connect to CREDENTIAL\n")); + GNUNET_SCHEDULER_shutdown (); + } + if (NULL == issuer_attr || NULL == subject_credential) + { + fprintf (stderr, + _("You must provide issuer and subject attributes\n")); + GNUNET_SCHEDULER_shutdown (); + } + + //Subject credentials are comma separated + char *tmp = GNUNET_strdup (subject_credential); + char *tok = strtok (tmp, ","); + if (NULL == tok) + { + fprintf (stderr, + "Invalid subject credentials\n"); + GNUNET_free (tmp); + GNUNET_SCHEDULER_shutdown (); + } + int count = 1; + int i; + while (NULL != (tok = strtok(NULL, ","))) + count++; + struct GNUNET_CREDENTIAL_Credential credentials[count]; + struct GNUNET_CREDENTIAL_Credential *cred; + GNUNET_free (tmp); + tmp = GNUNET_strdup (subject_credential); + tok = strtok (tmp, ","); + for (i=0;i<count;i++) + { + cred = GNUNET_CREDENTIAL_credential_from_string (tok); + GNUNET_memcpy (&credentials[i], + cred, + sizeof (struct GNUNET_CREDENTIAL_Credential)); + credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute); + tok = strtok(NULL, ","); + GNUNET_free (cred); + } + + verify_request = GNUNET_CREDENTIAL_verify(credential, + &issuer_pkey, + issuer_attr, //TODO argument + &subject_pkey, + count, + credentials, + &handle_verify_result, + NULL); + for (i=0;i<count;i++) + { + GNUNET_free ((char*)credentials[i].issuer_attribute); + } + } else if (GNUNET_YES == create_cred) { + if (NULL == ego_name) + { + fprintf (stderr, + _("Issuer ego required\n")); + GNUNET_SCHEDULER_shutdown (); + return; + + } + el = GNUNET_IDENTITY_ego_lookup (cfg, + ego_name, + &identity_cb, + (void *) cfg); + return; + } else { + fprintf (stderr, + _("Please specify name to lookup, subject key and issuer key!\n")); + GNUNET_SCHEDULER_shutdown (); + } + return; +} + + +/** + * The main function for gnunet-gns. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_flag ('I', + "issue", + gettext_noop ("create credential"), + &create_cred), + GNUNET_GETOPT_option_flag ('V', + "verify", + gettext_noop ("verify credential against attribute"), + &verify), + GNUNET_GETOPT_option_string ('s', + "subject", + "PKEY", + gettext_noop ("The public key of the subject to lookup the credential for"), + &subject_key), + GNUNET_GETOPT_option_string ('b', + "credential", + "CRED", + gettext_noop ("The name of the credential presented by the subject"), + &subject_credential), + GNUNET_GETOPT_option_string ('i', + "issuer", + "PKEY", + gettext_noop ("The public key of the authority to verify the credential against"), + &issuer_key), + GNUNET_GETOPT_option_string ('e', + "ego", + "EGO", + gettext_noop ("The ego to use"), + &ego_name), + GNUNET_GETOPT_option_string ('a', + "attribute", + "ATTR", + gettext_noop ("The issuer attribute to verify against or to issue"), + &issuer_attr), + GNUNET_GETOPT_option_string ('T', + "ttl", + "EXP", + gettext_noop ("The time to live for the credential"), + &expiration), + GNUNET_GETOPT_option_flag ('g', + "collect", + gettext_noop ("collect credentials"), + &collect), + GNUNET_GETOPT_OPTION_END + }; + int ret; + + timeout = GNUNET_TIME_UNIT_FOREVER_REL; + if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) + return 2; + + GNUNET_log_setup ("gnunet-credential", "WARNING", NULL); + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "gnunet-credential", + _("GNUnet credential resolver tool"), + options, + &run, NULL)) ? 0 : 1; + GNUNET_free ((void*) argv); + return ret; +} + +/* end of gnunet-credential.c */ diff --git a/src/credential/gnunet-service-credential.c b/src/credential/gnunet-service-credential.c new file mode 100644 index 000000000..be88839e9 --- /dev/null +++ b/src/credential/gnunet-service-credential.c @@ -0,0 +1,1160 @@ +/* + This file is part of GNUnet. + Copyright (C) 2011-2013 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/** + * @file credential/gnunet-service-credential.c + * @brief GNUnet Credential Service (main service) + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_credential_service.h" +#include "gnunet_statistics_service.h" +#include "credential.h" +#include "credential_serialization.h" +#include "gnunet_protocols.h" +#include "gnunet_signatures.h" + +#include <gnunet_dnsparser_lib.h> +#include <gnunet_identity_service.h> +#include <gnunet_gnsrecord_lib.h> +#include <gnunet_namestore_service.h> +#include <gnunet_gns_service.h> + + +#define GNUNET_CREDENTIAL_MAX_LENGTH 255 + +struct VerifyRequestHandle; + +struct DelegationSetQueueEntry; + + +struct DelegationChainEntry +{ + /** + * DLL + */ + struct DelegationChainEntry *next; + + /** + * DLL + */ + struct DelegationChainEntry *prev; + + /** + * The issuer + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * The subject + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * The issued attribute + */ + char *issuer_attribute; + + /** + * The delegated attribute + */ + char *subject_attribute; +}; + +/** + * DLL for record + */ +struct CredentialRecordEntry +{ + /** + * DLL + */ + struct CredentialRecordEntry *next; + + /** + * DLL + */ + struct CredentialRecordEntry *prev; + + /** + * Number of references in delegation chains + */ + uint32_t refcount; + + /** + * Payload + */ + struct GNUNET_CREDENTIAL_Credential *credential; +}; + +/** + * DLL used for delegations + * Used for OR delegations + */ +struct DelegationQueueEntry +{ + /** + * DLL + */ + struct DelegationQueueEntry *next; + + /** + * DLL + */ + struct DelegationQueueEntry *prev; + + /** + * Sets under this Queue + */ + struct DelegationSetQueueEntry *set_entries_head; + + /** + * Sets under this Queue + */ + struct DelegationSetQueueEntry *set_entries_tail; + + /** + * Parent set + */ + struct DelegationSetQueueEntry *parent_set; + + /** + * Required solutions + */ + uint32_t required_solutions; +}; + +/** + * DLL for delegation sets + * Used for AND delegation set + */ +struct DelegationSetQueueEntry +{ + /** + * DLL + */ + struct DelegationSetQueueEntry *next; + + /** + * DLL + */ + struct DelegationSetQueueEntry *prev; + + /** + * GNS handle + */ + struct GNUNET_GNS_LookupRequest *lookup_request; + + /** + * Verify handle + */ + struct VerifyRequestHandle *handle; + + /** + * Parent attribute delegation + */ + struct DelegationQueueEntry *parent; + + /** + * Issuer key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key; + + /** + * Queue entries of this set + */ + struct DelegationQueueEntry *queue_entries_head; + + /** + * Queue entries of this set + */ + struct DelegationQueueEntry *queue_entries_tail; + + /** + * Parent QueueEntry + */ + struct DelegationQueueEntry *parent_queue_entry; + + /** + * Issuer attribute delegated to + */ + char *issuer_attribute; + + /** + * The current attribute to look up + */ + char *lookup_attribute; + + /** + * Trailing attribute context + */ + char *attr_trailer; + + /** + * Still to resolve delegation as string + */ + char *unresolved_attribute_delegation; + + /** + * The delegation chain entry + */ + struct DelegationChainEntry *delegation_chain_entry; + +}; + + +/** + * Handle to a lookup operation from api + */ +struct VerifyRequestHandle +{ + + /** + * We keep these in a DLL. + */ + struct VerifyRequestHandle *next; + + /** + * We keep these in a DLL. + */ + struct VerifyRequestHandle *prev; + + /** + * Handle to the requesting client + */ + struct GNUNET_SERVICE_Client *client; + + /** + * GNS handle + */ + struct GNUNET_GNS_LookupRequest *lookup_request; + + /** + * Size of delegation tree + */ + uint32_t delegation_chain_size; + + /** + * Children of this attribute + */ + struct DelegationChainEntry *delegation_chain_head; + + /** + * Children of this attribute + */ + struct DelegationChainEntry *delegation_chain_tail; + + /** + * Issuer public key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Issuer attribute + */ + char *issuer_attribute; + + /** + * Subject public key + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Credential DLL + */ + struct CredentialRecordEntry *cred_chain_head; + + /** + * Credential DLL + */ + struct CredentialRecordEntry *cred_chain_tail; + + /** + * Credential DLL size + */ + uint32_t cred_chain_size; + + /** + * Root Delegation Set + */ + struct DelegationSetQueueEntry *root_set; + + /** + * Current Delegation Pointer + */ + struct DelegationQueueEntry *current_delegation; + + /** + * request id + */ + uint32_t request_id; + + /** + * Pending lookups + */ + uint64_t pending_lookups; + + /** + * Credential iterator + */ + struct GNUNET_NAMESTORE_ZoneIterator *cred_collection_iter; + + /** + * Collect task + */ + struct GNUNET_SCHEDULER_Task *collect_next_task; + +}; + + +/** + * Head of the DLL. + */ +static struct VerifyRequestHandle *vrh_head; + +/** + * Tail of the DLL. + */ +static struct VerifyRequestHandle *vrh_tail; + +/** + * Handle to the statistics service + */ +static struct GNUNET_STATISTICS_Handle *statistics; + +/** + * Handle to GNS service. + */ +static struct GNUNET_GNS_Handle *gns; + + +/** + * Handle to namestore service + */ +static struct GNUNET_NAMESTORE_Handle *namestore; + +static void +cleanup_delegation_set (struct DelegationSetQueueEntry *ds_entry) +{ + struct DelegationQueueEntry *dq_entry; + struct DelegationSetQueueEntry *child; + + if (NULL == ds_entry) + return; + + for (dq_entry = ds_entry->queue_entries_head; + NULL != dq_entry; + dq_entry = ds_entry->queue_entries_head) + { + GNUNET_CONTAINER_DLL_remove (ds_entry->queue_entries_head, + ds_entry->queue_entries_tail, + dq_entry); + for (child = dq_entry->set_entries_head; + NULL != child; + child = dq_entry->set_entries_head) + { + GNUNET_CONTAINER_DLL_remove (dq_entry->set_entries_head, + dq_entry->set_entries_tail, + child); + cleanup_delegation_set (child); + } + GNUNET_free (dq_entry); + } + GNUNET_free_non_null (ds_entry->issuer_key); + GNUNET_free_non_null (ds_entry->lookup_attribute); + GNUNET_free_non_null (ds_entry->issuer_attribute); + GNUNET_free_non_null (ds_entry->unresolved_attribute_delegation); + GNUNET_free_non_null (ds_entry->attr_trailer); + if (NULL != ds_entry->lookup_request) + { + GNUNET_GNS_lookup_cancel (ds_entry->lookup_request); + ds_entry->lookup_request = NULL; + } + if (NULL != ds_entry->delegation_chain_entry) + { + GNUNET_free_non_null (ds_entry->delegation_chain_entry->subject_attribute); + GNUNET_free_non_null (ds_entry->delegation_chain_entry->issuer_attribute); + GNUNET_free (ds_entry->delegation_chain_entry); + } + GNUNET_free (ds_entry); +} + +static void +cleanup_handle (struct VerifyRequestHandle *vrh) +{ + struct CredentialRecordEntry *cr_entry; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up...\n"); + if (NULL != vrh->lookup_request) + { + GNUNET_GNS_lookup_cancel (vrh->lookup_request); + vrh->lookup_request = NULL; + } + cleanup_delegation_set (vrh->root_set); + GNUNET_free_non_null (vrh->issuer_attribute); + for (cr_entry = vrh->cred_chain_head; + NULL != vrh->cred_chain_head; + cr_entry = vrh->cred_chain_head) + { + GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head, + vrh->cred_chain_tail, + cr_entry); + GNUNET_free_non_null (cr_entry->credential); + GNUNET_free (cr_entry); + } + GNUNET_free (vrh); +} + +static void +shutdown_task (void *cls) +{ + struct VerifyRequestHandle *vrh; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Shutting down!\n"); + + while (NULL != (vrh = vrh_head)) + { + //CREDENTIAL_resolver_lookup_cancel (clh->lookup); + GNUNET_CONTAINER_DLL_remove (vrh_head, + vrh_tail, + vrh); + cleanup_handle (vrh); + } + + if (NULL != gns) + { + GNUNET_GNS_disconnect (gns); + gns = NULL; + } + if (NULL != namestore) + { + GNUNET_NAMESTORE_disconnect (namestore); + namestore = NULL; + } + if (NULL != statistics) + { + GNUNET_STATISTICS_destroy (statistics, + GNUNET_NO); + statistics = NULL; + } + +} + + + +static void +send_lookup_response (struct VerifyRequestHandle *vrh) +{ + struct GNUNET_MQ_Envelope *env; + struct DelegationChainResultMessage *rmsg; + struct DelegationChainEntry *dce; + struct GNUNET_CREDENTIAL_Delegation dd[vrh->delegation_chain_size]; + struct GNUNET_CREDENTIAL_Credential cred[vrh->cred_chain_size]; + struct CredentialRecordEntry *cd; + struct CredentialRecordEntry *tmp; + size_t size; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending response\n"); + dce = vrh->delegation_chain_head; + for (uint32_t i=0;i<vrh->delegation_chain_size;i++) + { + dd[i].issuer_key = dce->issuer_key; + dd[i].subject_key = dce->subject_key; + dd[i].issuer_attribute = dce->issuer_attribute; + dd[i].issuer_attribute_len = strlen (dce->issuer_attribute)+1; + dd[i].subject_attribute_len = 0; + dd[i].subject_attribute = NULL; + if (NULL != dce->subject_attribute) + { + dd[i].subject_attribute = dce->subject_attribute; + dd[i].subject_attribute_len = strlen(dce->subject_attribute)+1; + } + dce = dce->next; + } + + /** + * Remove all credentials not needed + */ + for (cd = vrh->cred_chain_head; NULL != cd;) + { + if (cd->refcount > 0) + { + cd = cd->next; + continue; + } + tmp = cd; + cd = cd->next; + GNUNET_CONTAINER_DLL_remove (vrh->cred_chain_head, + vrh->cred_chain_tail, + tmp); + GNUNET_free (tmp->credential); + GNUNET_free (tmp); + vrh->cred_chain_size--; + } + + /** + * Get serialized record data + * Append at the end of rmsg + */ + cd = vrh->cred_chain_head; + for (uint32_t i=0;i<vrh->cred_chain_size;i++) + { + cred[i].issuer_key = cd->credential->issuer_key; + cred[i].subject_key = cd->credential->subject_key; + cred[i].issuer_attribute_len = strlen(cd->credential->issuer_attribute)+1; + cred[i].issuer_attribute = cd->credential->issuer_attribute; + cred[i].expiration = cd->credential->expiration; + cred[i].signature = cd->credential->signature; + cd = cd->next; + } + size = GNUNET_CREDENTIAL_delegation_chain_get_size (vrh->delegation_chain_size, + dd, + vrh->cred_chain_size, + cred); + env = GNUNET_MQ_msg_extra (rmsg, + size, + GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY_RESULT); + //Assign id so that client can find associated request + rmsg->id = vrh->request_id; + rmsg->d_count = htonl (vrh->delegation_chain_size); + rmsg->c_count = htonl (vrh->cred_chain_size); + + if (0 < vrh->cred_chain_size) + rmsg->cred_found = htonl (GNUNET_YES); + else + rmsg->cred_found = htonl (GNUNET_NO); + + GNUNET_assert (-1 != + GNUNET_CREDENTIAL_delegation_chain_serialize (vrh->delegation_chain_size, + dd, + vrh->cred_chain_size, + cred, + size, + (char*)&rmsg[1])); + + GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(vrh->client), + env); + GNUNET_CONTAINER_DLL_remove (vrh_head, vrh_tail, vrh); + cleanup_handle(vrh); + + GNUNET_STATISTICS_update (statistics, + "Completed verifications", 1, + GNUNET_NO); +} + + +static void +backward_resolution (void* cls, + uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + + struct VerifyRequestHandle *vrh; + const struct GNUNET_CREDENTIAL_DelegationRecord *sets; + struct CredentialRecordEntry *cred_pointer; + struct DelegationSetQueueEntry *current_set; + struct DelegationSetQueueEntry *ds_entry; + struct DelegationSetQueueEntry *tmp_set; + struct DelegationQueueEntry *dq_entry; + char *expanded_attr; + char *lookup_attribute; + + + current_set = cls; + current_set->lookup_request = NULL; + vrh = current_set->handle; + vrh->pending_lookups--; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got %d attrs\n", rd_count); + + // Each OR + for (uint32_t i=0; i < rd_count; i++) + { + if (GNUNET_GNSRECORD_TYPE_ATTRIBUTE != rd[i].record_type) + continue; + + sets = rd[i].data; + struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets->set_count)]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found new attribute delegation with %d sets. Creating new Job...\n", + ntohl (sets->set_count)); + + if (GNUNET_OK !=GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll(sets->data_size), + (const char*)&sets[1], + ntohl(sets->set_count), + set)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to deserialize!\n"); + continue; + } + dq_entry = GNUNET_new (struct DelegationQueueEntry); + dq_entry->required_solutions = ntohl(sets->set_count); + dq_entry->parent_set = current_set; + GNUNET_CONTAINER_DLL_insert (current_set->queue_entries_head, + current_set->queue_entries_tail, + dq_entry); + // Each AND + for (uint32_t j=0; j<ntohl(sets->set_count); j++) + { + ds_entry = GNUNET_new (struct DelegationSetQueueEntry); + if (NULL != current_set->attr_trailer) + { + if (0 == set[j].subject_attribute_len) + { + GNUNET_asprintf (&expanded_attr, + "%s", + current_set->attr_trailer); + + } else { + GNUNET_asprintf (&expanded_attr, + "%s.%s", + set[j].subject_attribute, + current_set->attr_trailer); + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Expanded to %s\n", expanded_attr); + ds_entry->unresolved_attribute_delegation = expanded_attr; + } else { + if (0 != set[j].subject_attribute_len) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Not Expanding %s\n", set[j].subject_attribute); + ds_entry->unresolved_attribute_delegation = GNUNET_strdup (set[j].subject_attribute); + } + } + + //Add a credential chain entry + ds_entry->delegation_chain_entry = GNUNET_new (struct DelegationChainEntry); + ds_entry->delegation_chain_entry->subject_key = set[j].subject_key; + ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey); + GNUNET_memcpy (ds_entry->issuer_key, + &set[j].subject_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + if (0 < set[j].subject_attribute_len) + ds_entry->delegation_chain_entry->subject_attribute = GNUNET_strdup (set[j].subject_attribute); + ds_entry->delegation_chain_entry->issuer_key = *current_set->issuer_key; + ds_entry->delegation_chain_entry->issuer_attribute = GNUNET_strdup (current_set->lookup_attribute); + + ds_entry->parent_queue_entry = dq_entry; //current_delegation; + GNUNET_CONTAINER_DLL_insert (dq_entry->set_entries_head, + dq_entry->set_entries_tail, + ds_entry); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking for cred match\n"); + /** + * Check if this delegation already matches one of our credentials + */ + for(cred_pointer = vrh->cred_chain_head; cred_pointer != NULL; + cred_pointer = cred_pointer->next) + { + if(0 != memcmp (&set->subject_key, + &cred_pointer->credential->issuer_key, + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) + continue; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Checking if %s matches %s\n", + ds_entry->unresolved_attribute_delegation, + cred_pointer->credential->issuer_attribute); + + if (0 != strcmp (ds_entry->unresolved_attribute_delegation, + cred_pointer->credential->issuer_attribute)) + continue; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found issuer\n"); + cred_pointer->refcount++; + //Backtrack + for (tmp_set = ds_entry; + NULL != tmp_set->parent_queue_entry; + tmp_set = tmp_set->parent_queue_entry->parent_set) + { + tmp_set->parent_queue_entry->required_solutions--; + if (NULL != tmp_set->delegation_chain_entry) + { + vrh->delegation_chain_size++; + GNUNET_CONTAINER_DLL_insert (vrh->delegation_chain_head, + vrh->delegation_chain_tail, + tmp_set->delegation_chain_entry); + } + if (0 < tmp_set->parent_queue_entry->required_solutions) + break; + } + + if (NULL == tmp_set->parent_queue_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All solutions found\n"); + //Found match + send_lookup_response (vrh); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Not all solutions found yet.\n"); + continue; + + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Building new lookup request from %s\n", + ds_entry->unresolved_attribute_delegation); + //Continue with backward resolution + char issuer_attribute_name[strlen (ds_entry->unresolved_attribute_delegation)+1]; + strcpy (issuer_attribute_name, + ds_entry->unresolved_attribute_delegation); + char *next_attr = strtok (issuer_attribute_name, "."); + GNUNET_asprintf (&lookup_attribute, + "%s.gnu", + next_attr); + GNUNET_asprintf (&ds_entry->lookup_attribute, + "%s", + next_attr); + if (strlen (next_attr) == strlen (ds_entry->unresolved_attribute_delegation)) + { + ds_entry->attr_trailer = NULL; + } else { + next_attr += strlen (next_attr) + 1; + ds_entry->attr_trailer = GNUNET_strdup (next_attr); + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up %s\n", ds_entry->lookup_attribute); + if (NULL != ds_entry->attr_trailer) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s still to go...\n", ds_entry->attr_trailer); + + vrh->pending_lookups++; + ds_entry->handle = vrh; + ds_entry->lookup_request = GNUNET_GNS_lookup (gns, + lookup_attribute, + ds_entry->issuer_key, //issuer_key, + GNUNET_GNSRECORD_TYPE_ATTRIBUTE, + GNUNET_GNS_LO_DEFAULT, + &backward_resolution, + ds_entry); + GNUNET_free (lookup_attribute); + } + } + + if(0 == vrh->pending_lookups) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "We are all out of attributes...\n"); + send_lookup_response (vrh); + return; + + } +} + + +/** + * Result from GNS lookup. + * + * @param cls the closure (our client lookup handle) + */ +static void +delegation_chain_resolution_start (void* cls) +{ + struct VerifyRequestHandle *vrh = cls; + struct DelegationSetQueueEntry *ds_entry; + struct CredentialRecordEntry *cr_entry; + vrh->lookup_request = NULL; + + if (0 == vrh->cred_chain_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No credentials found\n"); + send_lookup_response (vrh); + return; + } + + for (cr_entry = vrh->cred_chain_head; cr_entry != NULL; cr_entry = cr_entry->next) + { + if (0 != memcmp (&cr_entry->credential->issuer_key, + &vrh->issuer_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + continue; + if (0 != strcmp (cr_entry->credential->issuer_attribute, vrh->issuer_attribute)) + continue; + cr_entry->refcount++; + //Found match prematurely + send_lookup_response (vrh); + return; + + } + + /** + * Check for attributes from the issuer and follow the chain + * till you get the required subject's attributes + */ + char issuer_attribute_name[strlen (vrh->issuer_attribute)]; + strcpy (issuer_attribute_name, + vrh->issuer_attribute); + strcpy (issuer_attribute_name + strlen (vrh->issuer_attribute), + ".gnu"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up %s\n", issuer_attribute_name); + ds_entry = GNUNET_new (struct DelegationSetQueueEntry); + ds_entry->issuer_key = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPublicKey); + memcpy (ds_entry->issuer_key, + &vrh->issuer_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + ds_entry->issuer_attribute = GNUNET_strdup (vrh->issuer_attribute); + ds_entry->handle = vrh; + ds_entry->lookup_attribute = GNUNET_strdup (vrh->issuer_attribute); + vrh->root_set = ds_entry; + vrh->pending_lookups = 1; + //Start with backward resolution + ds_entry->lookup_request = GNUNET_GNS_lookup (gns, + issuer_attribute_name, + &vrh->issuer_key, //issuer_key, + GNUNET_GNSRECORD_TYPE_ATTRIBUTE, + GNUNET_GNS_LO_DEFAULT, + &backward_resolution, + ds_entry); +} + +static int +check_verify (void *cls, + const struct VerifyMessage *v_msg) +{ + size_t msg_size; + const char* attr; + + msg_size = ntohs (v_msg->header.size); + if (msg_size < sizeof (struct VerifyMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (ntohs (v_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + attr = (const char *) &v_msg[1]; + + if ( strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +static void +handle_verify (void *cls, + const struct VerifyMessage *v_msg) +{ + struct VerifyRequestHandle *vrh; + struct GNUNET_SERVICE_Client *client = cls; + struct CredentialRecordEntry *cr_entry; + uint32_t credentials_count; + uint32_t credential_data_size; + char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; + char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; + char *attrptr = attr; + char *credential_data; + const char *utf_in; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received VERIFY message\n"); + utf_in = (const char *) &v_msg[1]; + GNUNET_STRINGS_utf8_tolower (utf_in, attrptr); + GNUNET_memcpy (issuer_attribute, attr, ntohs (v_msg->issuer_attribute_len)); + issuer_attribute[ntohs (v_msg->issuer_attribute_len)] = '\0'; + vrh = GNUNET_new (struct VerifyRequestHandle); + GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh); + vrh->client = client; + vrh->request_id = v_msg->id; + vrh->issuer_key = v_msg->issuer_key; + vrh->subject_key = v_msg->subject_key; + vrh->issuer_attribute = GNUNET_strdup (issuer_attribute); + if (NULL == issuer_attribute) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No issuer attribute provided!\n"); + send_lookup_response (vrh); + return; + } + /** + * First, collect credentials + * TODO: cleanup! + */ + credentials_count = ntohl(v_msg->c_count); + credential_data_size = ntohs (v_msg->header.size) + - sizeof (struct VerifyMessage) + - ntohs (v_msg->issuer_attribute_len) + - 1; + struct GNUNET_CREDENTIAL_Credential credentials[credentials_count]; + credential_data = (char*)&v_msg[1] + ntohs (v_msg->issuer_attribute_len) + 1; + if (GNUNET_OK != GNUNET_CREDENTIAL_credentials_deserialize (credential_data_size, + credential_data, + credentials_count, + credentials)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot deserialize credentials!\n"); + send_lookup_response (vrh); + return; + } + + for (uint32_t i=0;i<credentials_count;i++) { + cr_entry = GNUNET_new (struct CredentialRecordEntry); + cr_entry->credential = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + + credentials[i].issuer_attribute_len); + GNUNET_memcpy (cr_entry->credential, + &credentials[i], + sizeof (struct GNUNET_CREDENTIAL_Credential)); + GNUNET_memcpy (&cr_entry->credential[1], + credentials[i].issuer_attribute, + credentials[i].issuer_attribute_len); + cr_entry->credential->issuer_attribute = (char*)&cr_entry->credential[1]; + GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head, + vrh->cred_chain_tail, + cr_entry); + vrh->cred_chain_size++; + } + + delegation_chain_resolution_start (vrh); + +} + +static void +handle_cred_collection_error_cb (void *cls) +{ + struct VerifyRequestHandle *vrh = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got disconnected from namestore database.\n"); + vrh->cred_collection_iter = NULL; + send_lookup_response (vrh); +} + +static void +collect_next (void *cls) +{ + struct VerifyRequestHandle *vrh = cls; + vrh->collect_next_task = NULL; + GNUNET_assert (NULL != vrh->cred_collection_iter); + GNUNET_NAMESTORE_zone_iterator_next (vrh->cred_collection_iter); +} + +static void +handle_cred_collection_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct VerifyRequestHandle *vrh = cls; + struct GNUNET_CREDENTIAL_Credential *crd; + struct CredentialRecordEntry *cr_entry; + int cred_record_count; + + cred_record_count = 0; + for (uint32_t i=0; i < rd_count; i++) + { + if (GNUNET_GNSRECORD_TYPE_CREDENTIAL != rd[i].record_type) + continue; + cred_record_count++; + crd = GNUNET_CREDENTIAL_credential_deserialize (rd[i].data, + rd[i].data_size); + if (NULL == crd) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid credential found\n"); + continue; + } + cr_entry = GNUNET_new (struct CredentialRecordEntry); + cr_entry->credential = crd; + GNUNET_CONTAINER_DLL_insert_tail (vrh->cred_chain_head, + vrh->cred_chain_tail, + cr_entry); + vrh->cred_chain_size++; + } + vrh->collect_next_task = GNUNET_SCHEDULER_add_now (&collect_next, + vrh); +} + +static void +handle_cred_collection_finished_cb (void *cls) +{ + struct VerifyRequestHandle *vrh = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Done collecting credentials.\n"); + vrh->cred_collection_iter = NULL; + delegation_chain_resolution_start (vrh); +} + +static void +handle_collect (void *cls, + const struct CollectMessage *c_msg) +{ + char attr[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; + char issuer_attribute[GNUNET_CREDENTIAL_MAX_LENGTH + 1]; + struct VerifyRequestHandle *vrh; + struct GNUNET_SERVICE_Client *client = cls; + char *attrptr = attr; + const char *utf_in; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received COLLECT message\n"); + + utf_in = (const char *) &c_msg[1]; + GNUNET_STRINGS_utf8_tolower (utf_in, attrptr); + + GNUNET_memcpy (issuer_attribute, attr, ntohs (c_msg->issuer_attribute_len)); + issuer_attribute[ntohs (c_msg->issuer_attribute_len)] = '\0'; + vrh = GNUNET_new (struct VerifyRequestHandle); + GNUNET_CONTAINER_DLL_insert (vrh_head, vrh_tail, vrh); + vrh->client = client; + vrh->request_id = c_msg->id; + vrh->issuer_key = c_msg->issuer_key; + GNUNET_CRYPTO_ecdsa_key_get_public (&c_msg->subject_key, + &vrh->subject_key); + vrh->issuer_attribute = GNUNET_strdup (issuer_attribute); + + if (NULL == issuer_attribute) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No issuer attribute provided!\n"); + send_lookup_response (vrh); + return; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Getting credentials for subject\n"); + /** + * First, get attribute from subject + */ + vrh->cred_collection_iter = GNUNET_NAMESTORE_zone_iteration_start (namestore, + &c_msg->subject_key, + &handle_cred_collection_error_cb, + vrh, + &handle_cred_collection_cb, + vrh, + &handle_cred_collection_finished_cb, + vrh); +} + + +static int +check_collect (void *cls, + const struct CollectMessage *c_msg) +{ + size_t msg_size; + const char* attr; + + msg_size = ntohs (c_msg->header.size); + if (msg_size < sizeof (struct CollectMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (ntohs (c_msg->issuer_attribute_len) > GNUNET_CREDENTIAL_MAX_LENGTH) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + attr = (const char *) &c_msg[1]; + + if ( ('\0' != attr[ntohs(c_msg->header.size) - sizeof (struct CollectMessage) - 1]) || + (strlen (attr) > GNUNET_CREDENTIAL_MAX_LENGTH) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + +static void +client_disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + void *app_ctx) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p disconnected\n", + client); +} + +static void * +client_connect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + struct GNUNET_MQ_Handle *mq) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %p connected\n", + client); + return client; +} + +/** + * Process Credential requests. + * + * @param cls closure + * @param c configuration to use + * @param handle service handle + */ +static void +run (void *cls, + const struct GNUNET_CONFIGURATION_Handle *c, + struct GNUNET_SERVICE_Handle *handle) +{ + + gns = GNUNET_GNS_connect (c); + if (NULL == gns) + { + fprintf (stderr, + _("Failed to connect to GNS\n")); + } + namestore = GNUNET_NAMESTORE_connect (c); + if (NULL == namestore) + { + fprintf (stderr, + _("Failed to connect to namestore\n")); + } + + statistics = GNUNET_STATISTICS_create ("credential", c); + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); +} + + +/** + * Define "main" method using service macro + */ +GNUNET_SERVICE_MAIN +("credential", + GNUNET_SERVICE_OPTION_NONE, + &run, + &client_connect_cb, + &client_disconnect_cb, + NULL, + GNUNET_MQ_hd_var_size (verify, + GNUNET_MESSAGE_TYPE_CREDENTIAL_VERIFY, + struct VerifyMessage, + NULL), + GNUNET_MQ_hd_var_size (collect, + GNUNET_MESSAGE_TYPE_CREDENTIAL_COLLECT, + struct CollectMessage, + NULL), + GNUNET_MQ_handler_end()); + +/* end of gnunet-service-credential.c */ diff --git a/src/credential/plugin_gnsrecord_credential.c b/src/credential/plugin_gnsrecord_credential.c new file mode 100644 index 000000000..342790b7a --- /dev/null +++ b/src/credential/plugin_gnsrecord_credential.c @@ -0,0 +1,353 @@ +/* + This file is part of GNUnet + Copyright (C) 2013 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file credential/plugin_gnsrecord_credential.c + * @brief gnsrecord plugin to provide the API for CREDENTIAL records + * @author Martin Schanzenbach + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_gnsrecord_lib.h" +#include "gnunet_credential_service.h" +#include "gnunet_gnsrecord_plugin.h" +#include "gnunet_signatures.h" +#include "credential_serialization.h" +#include "credential_misc.h" + +/** + * Convert the 'value' of a record to a string. + * + * @param cls closure, unused + * @param type type of the record + * @param data value in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the value + */ +static char * +credential_value_to_string (void *cls, + uint32_t type, + const void *data, + size_t data_size) +{ + + const char *cdata; + + switch (type) + { + case GNUNET_GNSRECORD_TYPE_ATTRIBUTE: + { + struct GNUNET_CREDENTIAL_DelegationRecord sets; + char *attr_str; + char *subject_pkey; + char *tmp_str; + int i; + if (data_size < sizeof (struct GNUNET_CREDENTIAL_DelegationRecord)) + return NULL; /* malformed */ + memcpy (&sets, + data, + sizeof (sets)); + cdata = data; + struct GNUNET_CREDENTIAL_DelegationSet set[ntohl(sets.set_count)]; + if (GNUNET_OK != GNUNET_CREDENTIAL_delegation_set_deserialize (GNUNET_ntohll (sets.data_size), + &cdata[sizeof (sets)], + ntohl (sets.set_count), + set)) + return NULL; + + for (i=0;i<ntohl(sets.set_count);i++) + { + subject_pkey = GNUNET_CRYPTO_ecdsa_public_key_to_string (&set[i].subject_key); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%d len attr\n", set[i].subject_attribute_len); + if (0 == set[i].subject_attribute_len) + { + if (0 == i) + { + GNUNET_asprintf (&attr_str, + "%s", + subject_pkey); + } else { + GNUNET_asprintf (&tmp_str, + "%s,%s", + attr_str, + subject_pkey); + GNUNET_free (attr_str); + attr_str = tmp_str; + } + } else { + if (0 == i) + { + GNUNET_asprintf (&attr_str, + "%s %s", + subject_pkey, + set[i].subject_attribute); + } else { + GNUNET_asprintf (&tmp_str, + "%s,%s %s", + attr_str, + subject_pkey, + set[i].subject_attribute); + GNUNET_free (attr_str); + attr_str = tmp_str; + } + } + GNUNET_free (subject_pkey); + } + return attr_str; + } + case GNUNET_GNSRECORD_TYPE_CREDENTIAL: + { + struct GNUNET_CREDENTIAL_Credential *cred; + char *cred_str; + + cred = GNUNET_CREDENTIAL_credential_deserialize (data, + data_size); + cred_str = GNUNET_CREDENTIAL_credential_to_string (cred); + GNUNET_free (cred); + return cred_str; + } + case GNUNET_GNSRECORD_TYPE_POLICY: + { + return GNUNET_strndup (data,data_size); + } + default: + return NULL; + } +} + + +/** + * Convert human-readable version of a 'value' of a record to the binary + * representation. + * + * @param cls closure, unused + * @param type type of the record + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +static int +credential_string_to_value (void *cls, + uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + if (NULL == s) + return GNUNET_SYSERR; + switch (type) + { + case GNUNET_GNSRECORD_TYPE_ATTRIBUTE: + { + struct GNUNET_CREDENTIAL_DelegationRecord *sets; + char attr_str[253 + 1]; + char subject_pkey[52 + 1]; + char *token; + char *tmp_str; + int matches = 0; + int entries; + size_t tmp_data_size; + int i; + + tmp_str = GNUNET_strdup (s); + token = strtok (tmp_str, ","); + entries = 0; + tmp_data_size = 0; + *data_size = sizeof (struct GNUNET_CREDENTIAL_DelegationRecord); + while (NULL != token) + { + matches = SSCANF (token, + "%s %s", + subject_pkey, + attr_str); + if (0 == matches) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unable to parse ATTR record string `%s'\n"), + s); + GNUNET_free (tmp_str); + return GNUNET_SYSERR; + } + if (1 == matches) { + tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet); + } else if (2 == matches) { + tmp_data_size += sizeof (struct GNUNET_CREDENTIAL_DelegationRecordSet) + strlen (attr_str) + 1; + } + entries++; + token = strtok (NULL, ","); + } + GNUNET_free (tmp_str); + tmp_str = GNUNET_strdup (s); + token = strtok (tmp_str, ","); + struct GNUNET_CREDENTIAL_DelegationSet set[entries]; + for (i=0;i<entries;i++) + { + matches = SSCANF (token, + "%s %s", + subject_pkey, + attr_str); + GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pkey, + strlen (subject_pkey), + &set[i].subject_key); + if (2 == matches) { + set[i].subject_attribute_len = strlen (attr_str) + 1; + set[i].subject_attribute = GNUNET_strdup (attr_str); + } + token = strtok (NULL , ","); + } + tmp_data_size = GNUNET_CREDENTIAL_delegation_set_get_size (entries, + set); + + if (-1 == tmp_data_size) + return GNUNET_SYSERR; + *data_size += tmp_data_size; + *data = sets = GNUNET_malloc (*data_size); + GNUNET_CREDENTIAL_delegation_set_serialize (entries, + set, + tmp_data_size, + (char*)&sets[1]); + for (i=0;i<entries;i++) + { + if (0 != set[i].subject_attribute_len) + GNUNET_free ((char*)set[i].subject_attribute); + } + sets->set_count = htonl (entries); + sets->data_size = GNUNET_htonll (tmp_data_size); + + GNUNET_free (tmp_str); + return GNUNET_OK; + } + case GNUNET_GNSRECORD_TYPE_CREDENTIAL: + { + struct GNUNET_CREDENTIAL_Credential *cred; + cred = GNUNET_CREDENTIAL_credential_from_string (s); + + *data_size = GNUNET_CREDENTIAL_credential_serialize (cred, + (char**)data); + return GNUNET_OK; + } + case GNUNET_GNSRECORD_TYPE_POLICY: + { + *data_size = strlen (s); + *data = GNUNET_strdup (s); + return GNUNET_OK; + } + default: + return GNUNET_SYSERR; + } +} + + +/** + * Mapping of record type numbers to human-readable + * record type names. + */ +static struct { + const char *name; + uint32_t number; +} name_map[] = { + { "CRED", GNUNET_GNSRECORD_TYPE_CREDENTIAL }, + { "ATTR", GNUNET_GNSRECORD_TYPE_ATTRIBUTE }, + { "POLICY", GNUNET_GNSRECORD_TYPE_POLICY }, + { NULL, UINT32_MAX } +}; + + +/** + * Convert a type name (i.e. "AAAA") to the corresponding number. + * + * @param cls closure, unused + * @param gns_typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +static uint32_t +credential_typename_to_number (void *cls, + const char *gns_typename) +{ + unsigned int i; + + i=0; + while ( (name_map[i].name != NULL) && + (0 != strcasecmp (gns_typename, name_map[i].name)) ) + i++; + return name_map[i].number; +} + + +/** + * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A") + * + * @param cls closure, unused + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +static const char * +credential_number_to_typename (void *cls, + uint32_t type) +{ + unsigned int i; + + i=0; + while ( (name_map[i].name != NULL) && + (type != name_map[i].number) ) + i++; + return name_map[i].name; +} + + +/** + * Entry point for the plugin. + * + * @param cls NULL + * @return the exported block API + */ +void * +libgnunet_plugin_gnsrecord_credential_init (void *cls) +{ + struct GNUNET_GNSRECORD_PluginFunctions *api; + + api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions); + api->value_to_string = &credential_value_to_string; + api->string_to_value = &credential_string_to_value; + api->typename_to_number = &credential_typename_to_number; + api->number_to_typename = &credential_number_to_typename; + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the return value from #libgnunet_plugin_block_test_init + * @return NULL + */ +void * +libgnunet_plugin_gnsrecord_credential_done (void *cls) +{ + struct GNUNET_GNSRECORD_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_gnsrecord_credential.c */ diff --git a/src/credential/plugin_rest_credential.c b/src/credential/plugin_rest_credential.c new file mode 100644 index 000000000..480658822 --- /dev/null +++ b/src/credential/plugin_rest_credential.c @@ -0,0 +1,1146 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/** + * @author Martin Schanzenbach + * @file credential/plugin_rest_credential.c + * @brief GNUnet CREDENTIAL REST plugin + * + */ + +#include "platform.h" +#include "gnunet_rest_plugin.h" +#include <gnunet_identity_service.h> +#include <gnunet_gnsrecord_lib.h> +#include <gnunet_namestore_service.h> +#include <gnunet_credential_service.h> +#include <gnunet_rest_lib.h> +#include <gnunet_jsonapi_lib.h> +#include <gnunet_jsonapi_util.h> +#include <jansson.h> + +#define GNUNET_REST_API_NS_CREDENTIAL "/credential" + +#define GNUNET_REST_API_NS_CREDENTIAL_ISSUE "/credential/issue" + +#define GNUNET_REST_API_NS_CREDENTIAL_VERIFY "/credential/verify" + +#define GNUNET_REST_API_NS_CREDENTIAL_COLLECT "/credential/collect" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION "expiration" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY "subject_key" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO "subject" + +#define GNUNET_REST_JSONAPI_CREDENTIAL "credential" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO "credential" + +#define GNUNET_REST_JSONAPI_DELEGATIONS "delegations" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR "attribute" + +#define GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_ATTR "credential" + +/** + * @brief struct returned by the initialization function of the plugin + */ +struct Plugin +{ + const struct GNUNET_CONFIGURATION_Handle *cfg; +}; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct RequestHandle +{ + /** + * Handle to Credential service. + */ + struct GNUNET_CREDENTIAL_Handle *credential; + + /** + * Handle to lookup request + */ + struct GNUNET_CREDENTIAL_Request *verify_request; + + /** + * Handle to issue request + */ + struct GNUNET_CREDENTIAL_Request *issue_request; + + /** + * Handle to identity + */ + struct GNUNET_IDENTITY_Handle *identity; + + /** + * Handle to identity operation + */ + struct GNUNET_IDENTITY_Operation *id_op; + + /** + * Handle to ego lookup + */ + struct GNUNET_IDENTITY_EgoLookup *ego_lookup; + + /** + * Handle to rest request + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + /** + * ID of a task associated with the resolution process. + */ + struct GNUNET_SCHEDULER_Task * timeout_task; + + /** + * The root of the received JSON or NULL + */ + json_t *json_root; + + /** + * The plugin result processor + */ + GNUNET_REST_ResultProcessor proc; + + /** + * The closure of the result processor + */ + void *proc_cls; + + /** + * The issuer attribute to verify + */ + char *issuer_attr; + + /** + * The subject attribute + */ + char *subject_attr; + + /** + * The public key of the issuer + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * The public key of the subject + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * HTTP response code + */ + int response_code; + + /** + * Timeout + */ + struct GNUNET_TIME_Relative timeout; + +}; + + +/** + * Cleanup lookup handle. + * + * @param handle Handle to clean up + */ +static void +cleanup_handle (struct RequestHandle *handle) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != handle->json_root) + json_decref (handle->json_root); + + if (NULL != handle->issuer_attr) + GNUNET_free (handle->issuer_attr); + if (NULL != handle->subject_attr) + GNUNET_free (handle->subject_attr); + if (NULL != handle->verify_request) + GNUNET_CREDENTIAL_request_cancel (handle->verify_request); + if (NULL != handle->credential) + GNUNET_CREDENTIAL_disconnect (handle->credential); + if (NULL != handle->id_op) + GNUNET_IDENTITY_cancel (handle->id_op); + if (NULL != handle->ego_lookup) + GNUNET_IDENTITY_ego_lookup_cancel (handle->ego_lookup); + if (NULL != handle->identity) + GNUNET_IDENTITY_disconnect (handle->identity); + if (NULL != handle->timeout_task) + { + GNUNET_SCHEDULER_cancel (handle->timeout_task); + } + GNUNET_free (handle); +} + + +static void +do_error (void *cls) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, handle->response_code); + cleanup_handle (handle); +} + +/** + * Attribute delegation to JSON + * + * @param delegation_chain_entry the DSE + * @return JSON, NULL if failed + */ +static json_t* +attribute_delegation_to_json (struct GNUNET_CREDENTIAL_Delegation *delegation_chain_entry) +{ + char *subject; + char *issuer; + json_t *attr_obj; + + issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->issuer_key); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Issuer in delegation malformed\n"); + return NULL; + } + subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&delegation_chain_entry->subject_key); + if (NULL == subject) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Subject in credential malformed\n"); + GNUNET_free (issuer); + return NULL; + } + attr_obj = json_object (); + + json_object_set_new (attr_obj, "issuer", json_string (issuer)); + json_object_set_new (attr_obj, "issuer_attribute", + json_string (delegation_chain_entry->issuer_attribute)); + + json_object_set_new (attr_obj, "subject", json_string (subject)); + if (0 < delegation_chain_entry->subject_attribute_len) + { + json_object_set_new (attr_obj, "subject_attribute", + json_string (delegation_chain_entry->subject_attribute)); + } + GNUNET_free (issuer); + GNUNET_free (subject); + return attr_obj; +} + +/** + * JSONAPI resource to Credential + * + * @param res the JSONAPI resource + * @return the resulting credential, NULL if failed + */ +static struct GNUNET_CREDENTIAL_Credential* +json_to_credential (json_t *res) +{ + struct GNUNET_CREDENTIAL_Credential *cred; + json_t *tmp; + const char *attribute; + const char *signature; + char *sig; + + tmp = json_object_get (res, "attribute"); + if (0 == json_is_string (tmp)) + { + return NULL; + } + attribute = json_string_value (tmp); + cred = GNUNET_malloc (sizeof (struct GNUNET_CREDENTIAL_Credential) + + strlen (attribute)); + cred->issuer_attribute = attribute; + cred->issuer_attribute_len = strlen (attribute); + tmp = json_object_get (res, "issuer"); + if (0 == json_is_string (tmp)) + { + GNUNET_free (cred); + return NULL; + } + + GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value(tmp), + strlen (json_string_value(tmp)), + &cred->issuer_key); + tmp = json_object_get (res, "subject"); + if (0 == json_is_string (tmp)) + { + GNUNET_free (cred); + return NULL; + } + GNUNET_CRYPTO_ecdsa_public_key_from_string (json_string_value(tmp), + strlen (json_string_value(tmp)), + &cred->subject_key); + + tmp = json_object_get (res, "signature"); + if (0 == json_is_string (tmp)) + { + GNUNET_free (cred); + return NULL; + } + signature = json_string_value (tmp); + GNUNET_STRINGS_base64_decode (signature, + strlen (signature), + (char**)&sig); + GNUNET_memcpy (&cred->signature, + sig, + sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); + GNUNET_free (sig); + + tmp = json_object_get (res, "expiration"); + if (0 == json_is_integer (tmp)) + { + GNUNET_free (cred); + return NULL; + } + cred->expiration.abs_value_us = json_integer_value (tmp); + return cred; +} + + +/** + * Credential to JSON + * + * @param cred the credential + * @return the resulting json, NULL if failed + */ +static json_t* +credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred) +{ + char *issuer; + char *subject; + char *signature; + char attribute[cred->issuer_attribute_len + 1]; + json_t *cred_obj; + + issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Issuer in credential malformed\n"); + return NULL; + } + subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key); + if (NULL == subject) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Subject in credential malformed\n"); + GNUNET_free (issuer); + return NULL; + } + GNUNET_STRINGS_base64_encode ((char*)&cred->signature, + sizeof (struct GNUNET_CRYPTO_EcdsaSignature), + &signature); + memcpy (attribute, + cred->issuer_attribute, + cred->issuer_attribute_len); + attribute[cred->issuer_attribute_len] = '\0'; + cred_obj = json_object (); + json_object_set_new (cred_obj, "issuer", json_string (issuer)); + json_object_set_new (cred_obj, "subject", json_string (subject)); + json_object_set_new (cred_obj, "attribute", json_string (attribute)); + json_object_set_new (cred_obj, "signature", json_string (signature)); + json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us)); + GNUNET_free (issuer); + GNUNET_free (subject); + GNUNET_free (signature); + return cred_obj; +} + +static void +handle_collect_response (void *cls, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *delegation_chain, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cred) +{ + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + struct GNUNET_JSONAPI_Document *json_document; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *cred_obj; + json_t *cred_array; + char *result; + char *issuer; + char *id; + uint32_t i; + + handle->verify_request = NULL; + if (NULL == cred) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Verify failed.\n"); + handle->response_code = MHD_HTTP_NOT_FOUND; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Issuer in delegation malformed\n"); + return; + } + GNUNET_asprintf (&id, + "%s.%s", + issuer, + handle->issuer_attr); + GNUNET_free (issuer); + json_document = GNUNET_JSONAPI_document_new (); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO, + id); + GNUNET_free (id); + cred_array = json_array (); + for (i=0;i<c_count;i++) + { + cred_obj = credential_to_json (&cred[i]); + json_array_append_new (cred_array, cred_obj); + } + GNUNET_JSONAPI_resource_add_attr (json_resource, + GNUNET_REST_JSONAPI_CREDENTIAL, + cred_array); + GNUNET_JSONAPI_document_resource_add (json_document, json_resource); + GNUNET_JSONAPI_document_serialize (json_document, &result); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Result %s\n", + result); + json_decref (cred_array); + GNUNET_JSONAPI_document_delete (json_document); + resp = GNUNET_REST_create_response (result); + GNUNET_free(result); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + cleanup_handle (handle); +} + +static void +subject_ego_lookup (void *cls, + const struct GNUNET_IDENTITY_Ego *ego) +{ + struct RequestHandle *handle = cls; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *sub_key; + handle->ego_lookup = NULL; + + if (NULL == ego) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Subject not found\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + sub_key = GNUNET_IDENTITY_ego_get_private_key (ego); + handle->verify_request = GNUNET_CREDENTIAL_collect (handle->credential, + &handle->issuer_key, + handle->issuer_attr, + sub_key, + &handle_collect_response, + handle); +} + + + +static void +handle_verify_response (void *cls, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *delegation_chain, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *cred) +{ + + struct RequestHandle *handle = cls; + struct MHD_Response *resp; + struct GNUNET_JSONAPI_Document *json_document; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *cred_obj; + json_t *attr_obj; + json_t *cred_array; + json_t *attr_array; + char *result; + char *issuer; + char *id; + uint32_t i; + + handle->verify_request = NULL; + if (NULL == cred) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Verify failed.\n"); + handle->response_code = MHD_HTTP_NOT_FOUND; + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&handle->issuer_key); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Issuer in delegation malformed\n"); + return; + } + GNUNET_asprintf (&id, + "%s.%s", + issuer, + handle->issuer_attr); + GNUNET_free (issuer); + json_document = GNUNET_JSONAPI_document_new (); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO, + id); + GNUNET_free (id); + attr_array = json_array (); + for (i = 0; i < d_count; i++) + { + attr_obj = attribute_delegation_to_json (&delegation_chain[i]); + json_array_append_new (attr_array, attr_obj); + } + cred_array = json_array (); + for (i=0;i<c_count;i++) + { + cred_obj = credential_to_json (&cred[i]); + json_array_append_new (cred_array, cred_obj); + } + GNUNET_JSONAPI_resource_add_attr (json_resource, + GNUNET_REST_JSONAPI_CREDENTIAL, + cred_array); + GNUNET_JSONAPI_resource_add_attr (json_resource, + GNUNET_REST_JSONAPI_DELEGATIONS, + attr_array); + GNUNET_JSONAPI_document_resource_add (json_document, json_resource); + GNUNET_JSONAPI_document_serialize (json_document, &result); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Result %s\n", + result); + json_decref (attr_array); + json_decref (cred_array); + GNUNET_JSONAPI_document_delete (json_document); + resp = GNUNET_REST_create_response (result); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result); + cleanup_handle (handle); +} + +static void +collect_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode key; + char *tmp; + char *entity_attr; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting...\n"); + handle->credential = GNUNET_CREDENTIAL_connect (cfg); + handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected\n"); + if (NULL == handle->credential) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Connecting to CREDENTIAL failed\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing issuer attribute\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + entity_attr = GNUNET_strdup (tmp); + tmp = strtok(entity_attr, "."); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed issuer or attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp, + strlen (tmp), + &handle->issuer_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed issuer key\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = strtok (NULL, "."); //Issuer attribute + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->issuer_attr = GNUNET_strdup (tmp); + GNUNET_free (entity_attr); + + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_EGO), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing subject\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->ego_lookup = GNUNET_IDENTITY_ego_lookup (cfg, + tmp, + &subject_ego_lookup, + handle); +} + + + +static void +verify_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode key; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *res; + struct GNUNET_CREDENTIAL_Credential *cred; + char *tmp; + char *entity_attr; + int i; + uint32_t credential_count; + uint32_t resource_count; + json_t *cred_json; + json_t *data_js; + json_error_t err; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting...\n"); + handle->credential = GNUNET_CREDENTIAL_connect (cfg); + handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected\n"); + if (NULL == handle->credential) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Connecting to CREDENTIAL failed\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing issuer attribute\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + entity_attr = GNUNET_strdup (tmp); + tmp = strtok(entity_attr, "."); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed issuer or attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp, + strlen (tmp), + &handle->issuer_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed issuer key\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = strtok (NULL, "."); //Issuer attribute + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed attribute\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->issuer_attr = GNUNET_strdup (tmp); + GNUNET_free (entity_attr); + + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (conndata_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing subject key\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (conndata_handle->url_param_map, + &key); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp, + strlen (tmp), + &handle->subject_key)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject key\n"); + GNUNET_free (entity_attr); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + if (0 >= handle->rest_handle->data_size) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing credentials\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + char term_data[handle->rest_handle->data_size+1]; + term_data[handle->rest_handle->data_size] = '\0'; + credential_count = 0; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_js = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (data_js, docspec, + NULL, NULL)); + json_decref (data_js); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + resource_count = GNUNET_JSONAPI_document_resource_count(json_obj); + GNUNET_assert (1 == resource_count); + res = (GNUNET_JSONAPI_document_get_resource(json_obj, 0)); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type(res, + GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Resource not a credential!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_JSONAPI_document_delete (json_obj); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + cred_json = GNUNET_JSONAPI_resource_read_attr (res, + GNUNET_REST_JSONAPI_CREDENTIAL); + + GNUNET_assert (json_is_array (cred_json)); + + credential_count = json_array_size(cred_json); + + struct GNUNET_CREDENTIAL_Credential credentials[credential_count]; + for (i=0;i<credential_count;i++) + { + cred = json_to_credential (json_array_get (cred_json, i)); + if (NULL == cred) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse credential!\n"); + continue; + } + GNUNET_memcpy (&credentials[i], + cred, + sizeof (struct GNUNET_CREDENTIAL_Credential)); + credentials[i].issuer_attribute = GNUNET_strdup (cred->issuer_attribute); + GNUNET_free (cred); + } + GNUNET_JSONAPI_document_delete(json_obj); + handle->verify_request = GNUNET_CREDENTIAL_verify (handle->credential, + &handle->issuer_key, + handle->issuer_attr, + &handle->subject_key, + credential_count, + credentials, + &handle_verify_response, + handle); + for (i=0;i<credential_count;i++) + GNUNET_free ((char*)credentials[i].issuer_attribute); + +} + +void +send_cred_response (struct RequestHandle *handle, + struct GNUNET_CREDENTIAL_Credential *cred) +{ + struct MHD_Response *resp; + struct GNUNET_JSONAPI_Document *json_document; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *cred_obj; + char *result; + char *issuer; + char *subject; + char *signature; + char *id; + + GNUNET_assert (NULL != cred); + issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key); + if (NULL == issuer) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Subject malformed\n"); + return; + } + GNUNET_asprintf (&id, + "%s.%s", + issuer, + (char*)&cred[1]); + subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key); + if (NULL == subject) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Subject malformed\n"); + return; + } + GNUNET_STRINGS_base64_encode ((char*)&cred->signature, + sizeof (struct GNUNET_CRYPTO_EcdsaSignature), + &signature); + json_document = GNUNET_JSONAPI_document_new (); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_CREDENTIAL_TYPEINFO, + id); + GNUNET_free (id); + cred_obj = json_object(); + json_object_set_new (cred_obj, "issuer", json_string (issuer)); + json_object_set_new (cred_obj, "subject", json_string (subject)); + json_object_set_new (cred_obj, "expiration", json_integer( cred->expiration.abs_value_us)); + json_object_set_new (cred_obj, "signature", json_string (signature)); + GNUNET_JSONAPI_resource_add_attr (json_resource, + GNUNET_REST_JSONAPI_CREDENTIAL, + cred_obj); + GNUNET_JSONAPI_document_resource_add (json_document, json_resource); + GNUNET_JSONAPI_document_serialize (json_document, &result); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Result %s\n", + result); + json_decref (cred_obj); + GNUNET_JSONAPI_document_delete (json_document); + resp = GNUNET_REST_create_response (result); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result); + GNUNET_free (signature); + GNUNET_free (issuer); + GNUNET_free (subject); + cleanup_handle (handle); +} + +void +get_cred_issuer_cb (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + struct RequestHandle *handle = cls; + struct GNUNET_TIME_Absolute etime_abs; + struct GNUNET_TIME_Relative etime_rel; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *issuer_key; + struct GNUNET_HashCode key; + struct GNUNET_CREDENTIAL_Credential *cred; + char* expiration_str; + char* tmp; + + handle->id_op = NULL; + + if (NULL == name) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Issuer not configured!\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connecting to credential service...\n"); + handle->credential = GNUNET_CREDENTIAL_connect (cfg); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Connected\n"); + if (NULL == handle->credential) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Connecting to CREDENTIAL failed\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_EXPIRATION), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing expiration\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + expiration_str = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, + &key); + if (GNUNET_OK == GNUNET_STRINGS_fancy_time_to_relative (expiration_str, + &etime_rel)) + { + etime_abs = GNUNET_TIME_relative_to_absolute (etime_rel); + } else if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (expiration_str, + &etime_abs)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed expiration: %s\n", expiration_str); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_ISSUER_ATTR), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing issuer attribute\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + handle->issuer_attr = GNUNET_strdup(GNUNET_CONTAINER_multihashmap_get + (handle->rest_handle->url_param_map, + &key)); + GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY, + strlen (GNUNET_REST_JSONAPI_CREDENTIAL_SUBJECT_KEY), + &key); + if ( GNUNET_NO == + GNUNET_CONTAINER_multihashmap_contains (handle->rest_handle->url_param_map, + &key) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Missing subject\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + tmp = GNUNET_CONTAINER_multihashmap_get (handle->rest_handle->url_param_map, + &key); + if (NULL == tmp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_public_key_from_string (tmp, + strlen (tmp), + &handle->subject_key)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Malformed subject key\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + issuer_key = GNUNET_IDENTITY_ego_get_private_key (ego); + cred = GNUNET_CREDENTIAL_credential_issue (issuer_key, + &handle->subject_key, + handle->issuer_attr, + &etime_abs); + if (NULL == cred) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to create credential\n"); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + send_cred_response (handle, cred); +} + + +static void +issue_cred_cont (struct GNUNET_REST_RequestHandle *conndata_handle, + const char* url, + void *cls) +{ + struct RequestHandle *handle = cls; + + handle->identity = GNUNET_IDENTITY_connect (cfg, + NULL, + NULL); + handle->id_op = GNUNET_IDENTITY_get(handle->identity, + "credential-issuer", + &get_cred_issuer_cb, + handle); + handle->timeout_task = GNUNET_SCHEDULER_add_delayed (handle->timeout, + &do_error, + handle); +} + +static void +options_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + struct MHD_Response *resp; + struct RequestHandle *handle = cls; + + //For GNS, independent of path return all options + resp = GNUNET_REST_create_response (NULL); + MHD_add_response_header (resp, + "Access-Control-Allow-Methods", + MHD_HTTP_METHOD_GET); + handle->proc (handle->proc_cls, + resp, + MHD_HTTP_OK); + cleanup_handle (handle); +} + + +static void +rest_credential_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, + GNUNET_REST_ResultProcessor proc, + void *proc_cls) +{ + struct RequestHandle *handle = GNUNET_new (struct RequestHandle); + struct GNUNET_REST_RequestHandlerError err; + + handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; + handle->proc_cls = proc_cls; + handle->proc = proc; + handle->rest_handle = conndata_handle; + + static const struct GNUNET_REST_RequestHandler handlers[] = { + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_CREDENTIAL_VERIFY, &verify_cred_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_COLLECT, &collect_cred_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_CREDENTIAL_ISSUE, &issue_cred_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_CREDENTIAL, &options_cont}, + GNUNET_REST_HANDLER_END + }; + + if (GNUNET_NO == GNUNET_JSONAPI_handle_request (conndata_handle, + handlers, + &err, + handle)) + { + handle->response_code = err.error_code; + GNUNET_SCHEDULER_add_now (&do_error, handle); + } +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_NAMESTORE_PluginEnvironment*" + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_rest_credential_init (void *cls) +{ + static struct Plugin plugin; + cfg = cls; + struct GNUNET_REST_Plugin *api; + + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + api = GNUNET_new (struct GNUNET_REST_Plugin); + api->cls = &plugin; + api->name = GNUNET_REST_API_NS_CREDENTIAL; + api->process_request = &rest_credential_process_request; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("GNS REST API initialized\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_rest_credential_done (void *cls) +{ + struct GNUNET_REST_Plugin *api = cls; + struct Plugin *plugin = api->cls; + + plugin->cfg = NULL; + GNUNET_free (api); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "GNS REST plugin is finished\n"); + return NULL; +} + +/* end of plugin_rest_gns.c */ diff --git a/src/credential/test_credential_collect.sh b/src/credential/test_credential_collect.sh new file mode 100755 index 000000000..6c713063f --- /dev/null +++ b/src/credential/test_credential_collect.sh @@ -0,0 +1,47 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +TEST_ATTR2="test2" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C testissuer -c test_credential_lookup.conf +gnunet-identity -C testsubject -c test_credential_lookup.conf +SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}') +ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}') +#TODO1 Get credential and store it with subject (3) +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf` +$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR2 --ttl=5m -c test_credential_lookup.conf` +$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c2 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf +CREDS=`$DO_TIMEOUT gnunet-credential --collect --issuer=$ISSUER_KEY --attribute=$TEST_ATTR --ego=testsubject -c test_credential_lookup.conf | paste -d, -s` +echo $CREDS +RES=$? +gnunet-arm -e -c test_credential_lookup.conf + +if test $? != 0 +then + echo "Error collecting..." + exit 1 +fi + diff --git a/src/credential/test_credential_collect_rest.sh b/src/credential/test_credential_collect_rest.sh new file mode 100755 index 000000000..0b31f85bc --- /dev/null +++ b/src/credential/test_credential_collect_rest.sh @@ -0,0 +1,90 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) Service.user -> GNU.project.member +# (2) GNU.project -> GNUnet +# (3) GNUnet.member -> GNUnet.developer +# (4) GNUnet.member -> GNUnet.user +# (5) GNUnet.developer -> Alice + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C service -c test_credential_lookup.conf +gnunet-identity -C alice -c test_credential_lookup.conf +gnunet-identity -C gnu -c test_credential_lookup.conf +gnunet-identity -C gnunet -c test_credential_lookup.conf + +GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}') +ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}') +GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}') +SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}') + +USER_ATTR="user" +GNU_PROJECT_ATTR="project" +MEMBER_ATTR="member" +DEVELOPER_ATTR="developer" +DEV_ATTR="developer" +TEST_CREDENTIAL="mygnunetcreds" + +# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU +gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf + +# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute +gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf + +# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user" +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf` + +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$USER_ATTR --ttl=5m -c test_credential_lookup.conf` + +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +#TODO2 Add -z swich like in gnunet-gns +#RES_CRED=`gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY -c test_credential_lookup.conf` + +gnunet-arm -i rest -c test_credential_lookup.conf + +sleep 5 + +curl -v "localhost:7776/credential/collect?attribute=$SERVICE_KEY.$USER_ATTR&subject=alice" + +#TODO cleanup properly +gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf +gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf +echo "Stopping arm..." +gnunet-arm -e -c test_credential_lookup.conf +echo "Done" +if [ "$RES_CRED" != "Failed." ] +then + echo -e "${RES_CRED}" + exit 0 +else + echo "FAIL: Failed to verify credential $RES_CRED." + exit 1 +fi diff --git a/src/credential/test_credential_defaults.conf b/src/credential/test_credential_defaults.conf new file mode 100644 index 000000000..d157ddd43 --- /dev/null +++ b/src/credential/test_credential_defaults.conf @@ -0,0 +1,24 @@ +@INLINE@ ../../contrib/no_forcestart.conf + +[PATHS] +GNUNET_TEST_HOME = /tmp/test-gnunet-credential-testing/ + +[namestore-sqlite] +FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db + +[namecache-sqlite] +FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db + +[identity] +# Directory where we store information about our egos +EGODIR = $GNUNET_TEST_HOME/identity/egos/ + +[dhtcache] +DATABASE = heap + +[transport] +PLUGINS = tcp + +[transport-tcp] +BINDTO = 127.0.0.1 + diff --git a/src/credential/test_credential_issue.sh b/src/credential/test_credential_issue.sh new file mode 100755 index 000000000..158d91c5b --- /dev/null +++ b/src/credential/test_credential_issue.sh @@ -0,0 +1,44 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C testissuer -c test_credential_lookup.conf +gnunet-identity -C testsubject -c test_credential_lookup.conf +SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}') +ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}') +#TODO1 Get credential and store it with subject (3) +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf` +STATUS=$? + +if test $? != 0 +then + echo "Error issuing..." + exit 1 +fi +#Try import +$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf +RES=$? +gnunet-arm -e -c test_credential_lookup.conf +exit $RES diff --git a/src/credential/test_credential_issue_rest.sh b/src/credential/test_credential_issue_rest.sh new file mode 100755 index 000000000..15cd55083 --- /dev/null +++ b/src/credential/test_credential_issue_rest.sh @@ -0,0 +1,53 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-arm -i gns +gnunet-arm -i credential +gnunet-arm -i identity +gnunet-arm -i rest -c test_credential_lookup.conf + +gnunet-arm -I -c test_credential_lookup.conf +gnunet-identity -C testissuer -c test_credential_lookup.conf +gnunet-identity -C testsubject -c test_credential_lookup.conf +gnunet-identity -s credential-issuer -e testissuer +SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}') +ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}') +#TODO1 Get credential and store it with subject (3) +sleep 5 +curl "localhost:7776/credential/issue?subject_key=$SUBJECT_KEY&attribute=$TEST_ATTR&expiration=1d" +#CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf` +STATUS=$? + +if test $? != 0 +then + echo "Error issuing..." + exit 1 +fi +#Try import +#$DO_TIMEOUT gnunet-namestore -a -z testsubject -n c1 -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf +RES=$? +gnunet-arm -e -c test_credential_lookup.conf +exit $RES diff --git a/src/credential/test_credential_lookup.conf b/src/credential/test_credential_lookup.conf new file mode 100644 index 000000000..3684063b1 --- /dev/null +++ b/src/credential/test_credential_lookup.conf @@ -0,0 +1,28 @@ +@INLINE@ test_credential_defaults.conf + +[PATHS] +GNUNET_TEST_HOME = /tmp/test-gnunet-credential-peer-1/ + +[dht] +AUTOSTART = YES + +[transport] +PLUGINS = + +[credential] +AUTOSTART = YES +PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/credlog + +[rest] +PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog + +[gns] +#PREFIX = valgrind --leak-check=full --track-origins=yes +AUTOSTART = YES +AUTO_IMPORT_PKEY = YES +MAX_PARALLEL_BACKGROUND_QUERIES = 10 +DEFAULT_LOOKUP_TIMEOUT = 15 s +RECORD_PUT_INTERVAL = 1 h +ZONE_PUBLISH_TIME_WINDOW = 1 h +DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 + diff --git a/src/credential/test_credential_verify.sh b/src/credential/test_credential_verify.sh new file mode 100755 index 000000000..d042bcfe6 --- /dev/null +++ b/src/credential/test_credential_verify.sh @@ -0,0 +1,81 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) Service.user -> GNU.project.member +# (2) GNU.project -> GNUnet +# (3) GNUnet.member -> GNUnet.developer +# (4) GNUnet.member -> GNUnet.user +# (5) GNUnet.developer -> Alice + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C service -c test_credential_lookup.conf +gnunet-identity -C alice -c test_credential_lookup.conf +gnunet-identity -C gnu -c test_credential_lookup.conf +gnunet-identity -C gnunet -c test_credential_lookup.conf + +GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}') +ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}') +GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}') +SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}') + +USER_ATTR="user" +GNU_PROJECT_ATTR="project" +MEMBER_ATTR="member" +DEVELOPER_ATTR="developer" +DEV_ATTR="developer" +TEST_CREDENTIAL="mygnunetcreds" + +# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU +gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf + +# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute +gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf + +# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user" +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf` + +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +CREDS=`$DO_TIMEOUT gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --ego=alice -c test_credential_lookup.conf | paste -d, -s` + +echo gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential=\'$CREDS\' -c test_credential_lookup.conf +#TODO2 Add -z swich like in gnunet-gns +gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential="$CREDS" -c test_credential_lookup.conf + + +#TODO cleanup properly +gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf +gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-arm -e -c test_credential_lookup.conf + +if [ "$RES_CRED" != "Failed." ] +then + echo -e "${RES_CRED}" + exit 0 +else + echo "FAIL: Failed to verify credential $RES_CRED." + exit 1 +fi diff --git a/src/credential/test_credential_verify_and.sh b/src/credential/test_credential_verify_and.sh new file mode 100755 index 000000000..9d5c1962e --- /dev/null +++ b/src/credential/test_credential_verify_and.sh @@ -0,0 +1,81 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) Service.user -> GNU.project.member +# (2) GNU.project -> GNUnet +# (3) GNUnet.member -> GNUnet.developer +# (4) GNUnet.member -> GNUnet.user +# (5) GNUnet.developer -> Alice + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C service -c test_credential_lookup.conf +gnunet-identity -C alice -c test_credential_lookup.conf +gnunet-identity -C gnu -c test_credential_lookup.conf +gnunet-identity -C gnunet -c test_credential_lookup.conf + +GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}') +ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}') +GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}') +SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}') + +USER_ATTR="user" +GNU_PROJECT_ATTR="project" +MEMBER_ATTR="member" +DEVELOPER_ATTR="developer" +DEV_ATTR="developer" +TEST_CREDENTIAL="mygnunetcreds" + +# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU +gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf + +# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute +gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf + +# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user" +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR,$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED1=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf` +# (5) GNUnet issues Alice the credential "user" +CRED2=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$USER_ATTR --ttl=5m -c test_credential_lookup.conf` +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED1" -e 5m -c test_credential_lookup.conf +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED2" -e 5m -c test_credential_lookup.conf + +CREDS=`$DO_TIMEOUT gnunet-credential --collect --issuer=$SERVICE_KEY --attribute=$USER_ATTR --ego=alice -c test_credential_lookup.conf | paste -d, -s` + +#TODO2 Add -z swich like in gnunet-gns +RES_CRED=`gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential="$CREDS" -c test_credential_lookup.conf` + + +#TODO cleanup properly +gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf +gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-arm -e -c test_credential_lookup.conf + +if [ "$RES_CRED" != "Failed." ] +then + echo -e "${RES_CRED}" + exit 0 +else + echo "FAIL: Failed to verify credential $RES_CRED." + exit 1 +fi diff --git a/src/credential/test_credential_verify_rest.sh b/src/credential/test_credential_verify_rest.sh new file mode 100755 index 000000000..6133ea25e --- /dev/null +++ b/src/credential/test_credential_verify_rest.sh @@ -0,0 +1,87 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (1) Service.user -> GNU.project.member +# (2) GNU.project -> GNUnet +# (3) GNUnet.member -> GNUnet.developer +# (4) GNUnet.member -> GNUnet.user +# (5) GNUnet.developer -> Alice + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C service -c test_credential_lookup.conf +gnunet-identity -C alice -c test_credential_lookup.conf +gnunet-identity -C gnu -c test_credential_lookup.conf +gnunet-identity -C gnunet -c test_credential_lookup.conf + +GNU_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnu | grep -v gnunet | awk '{print $3}') +ALICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep alice | awk '{print $3}') +GNUNET_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep gnunet | awk '{print $3}') +SERVICE_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep service | awk '{print $3}') + +USER_ATTR="user" +GNU_PROJECT_ATTR="project" +MEMBER_ATTR="member" +DEVELOPER_ATTR="developer" +DEV_ATTR="developer" +TEST_CREDENTIAL="mygnunetcreds" + +# (1) A service assigns the attribute "user" to all entities that have been assigned "member" by entities that werde assigned "project" from GNU +gnunet-namestore -p -z service -a -n $USER_ATTR -t ATTR -V "$GNU_KEY $GNU_PROJECT_ATTR.$MEMBER_ATTR" -e 5m -c test_credential_lookup.conf + +# (2) GNU recognized GNUnet as a GNU project and delegates the "project" attribute +gnunet-namestore -p -z gnu -a -n $GNU_PROJECT_ATTR -t ATTR -V "$GNUNET_KEY" -e 5m -c test_credential_lookup.conf + +# (3+4) GNUnet assigns the attribute "member" to all entities gnunet has also assigned "developer" or "user" +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $DEVELOPER_ATTR" -e 5m -c test_credential_lookup.conf +gnunet-namestore -p -z gnunet -a -n $MEMBER_ATTR -t ATTR -V "$GNUNET_KEY $USER_ATTR" -e 5m -c test_credential_lookup.conf + +# (5) GNUnet issues Alice the credential "developer" +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=gnunet --subject=$ALICE_KEY --attribute=$DEV_ATTR --ttl=5m -c test_credential_lookup.conf` + +# Alice stores the credential under "mygnunetcreds" +gnunet-namestore -p -z alice -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +#TODO2 Add -z swich like in gnunet-gns +#RES_CRED=`gnunet-credential --verify --issuer=$SERVICE_KEY --attribute=$USER_ATTR --subject=$ALICE_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf` + +gnunet-arm -i rest -c test_credential_lookup.conf + +sleep 5 + +CREDS=`curl "localhost:7776/credential/collect?attribute=$SERVICE_KEY.$USER_ATTR&subject=alice"` + +echo $CREDS + +curl -v "localhost:7776/credential/verify?attribute=$SERVICE_KEY.$USER_ATTR&subject_key=$ALICE_KEY" --data "$CREDS" + +#TODO cleanup properly +gnunet-namestore -z alice -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf +gnunet-namestore -z gnu -d -n $GNU_PROJECT_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z gnunet -d -n $MEMBER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-namestore -z service -d -n $USER_ATTR -t ATTR -c test_credential_lookup.conf +gnunet-arm -e -c test_credential_lookup.conf + +if [ "$RES_CRED" != "Failed." ] +then + echo -e "${RES_CRED}" + exit 0 +else + echo "FAIL: Failed to verify credential $RES_CRED." + exit 1 +fi diff --git a/src/credential/test_credential_verify_simple.sh b/src/credential/test_credential_verify_simple.sh new file mode 100755 index 000000000..c4fd8c7a3 --- /dev/null +++ b/src/credential/test_credential_verify_simple.sh @@ -0,0 +1,50 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_credential_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_credential_lookup.conf -s PATHS -o GNUNET_HOME -f` + +# (3) Isser.user -> Subject + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" +gnunet-arm -s -c test_credential_lookup.conf +gnunet-identity -C testissuer -c test_credential_lookup.conf +gnunet-identity -C testsubject -c test_credential_lookup.conf + +TEST_ATTR="user" +SUBJECT_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testsubject | awk '{print $3}') +ISSUER_KEY=$(gnunet-identity -d -c test_credential_lookup.conf | grep testissuer | awk '{print $3}') +CRED=`$DO_TIMEOUT gnunet-credential --issue --ego=testissuer --subject=$SUBJECT_KEY --attribute=$TEST_ATTR --ttl=5m -c test_credential_lookup.conf` + +TEST_CREDENTIAL="t1" +gnunet-namestore -p -z testsubject -a -n $TEST_CREDENTIAL -t CRED -V "$CRED" -e 5m -c test_credential_lookup.conf + +#TODO2 Add -z swich like in gnunet-gns +#RES_CRED=`$DO_TIMEOUT gnunet-credential --verify --issuer=$ISSUER_KEY --attribute="$TEST_ATTR" --subject=$SUBJECT_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf` +RES_CRED=`gnunet-credential --verify --issuer=$ISSUER_KEY --attribute=$TEST_ATTR --subject=$SUBJECT_KEY --credential=$TEST_CREDENTIAL -c test_credential_lookup.conf` + +#TODO cleanup properly +gnunet-namestore -z testsubject -d -n $TEST_CREDENTIAL -t CRED -e never -c test_credential_lookup.conf +gnunet-identity -D testsubject -c test_credential_lookup.conf +gnunet-arm -e -c test_credential_lookup.conf +echo $RES_CRED +#TODO3 proper test +if [ "$RES_CRED" == "Successful." ] +then + exit 0 +else + echo "FAIL: Failed to verify credential." + exit 1 +fi diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c index 7196a1844..d9a5dd684 100644 --- a/src/exit/gnunet-daemon-exit.c +++ b/src/exit/gnunet-daemon-exit.c @@ -3802,7 +3802,7 @@ run (void *cls, if (GNUNET_YES != GNUNET_OS_check_helper_binary (binary, GNUNET_YES, - "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")) //no nat, ipv4 only + "gnunet-vpn - - - 169.1.3.7 255.255.255.0")) //no nat, ipv4 only { GNUNET_free (binary); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c index 26293f4df..84c4ae189 100644 --- a/src/gns/gns_api.c +++ b/src/gns/gns_api.c @@ -244,10 +244,7 @@ handle_result (void *cls, return; proc = lr->lookup_proc; proc_cls = lr->proc_cls; - GNUNET_CONTAINER_DLL_remove (handle->lookup_head, - handle->lookup_tail, - lr); - GNUNET_free (lr); + GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_records_deserialize (mlen, (const char*) &lookup_msg[1], @@ -256,6 +253,12 @@ handle_result (void *cls, proc (proc_cls, rd_count, rd); + GNUNET_CONTAINER_DLL_remove (handle->lookup_head, + handle->lookup_tail, + lr); + if (NULL != lr->env) + GNUNET_MQ_discard (lr->env); + GNUNET_free (lr); } diff --git a/src/gns/plugin_gnsrecord_gns.c b/src/gns/plugin_gnsrecord_gns.c index 5d611e19e..6adad0f34 100644 --- a/src/gns/plugin_gnsrecord_gns.c +++ b/src/gns/plugin_gnsrecord_gns.c @@ -140,30 +140,6 @@ gns_value_to_string (void *cls, GNUNET_free (ival); return box_str; } - case GNUNET_GNSRECORD_TYPE_REVERSE: - { - struct GNUNET_GNSRECORD_ReverseRecord rev; - char *rev_str; - char *pkey_str; - - if (data_size < sizeof (struct GNUNET_GNSRECORD_ReverseRecord)) - return NULL; /* malformed */ - - memcpy (&rev, - data, - sizeof (rev)); - cdata = data; - pkey_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&rev.pkey); - - GNUNET_asprintf (&rev_str, - "%s %s %"SCNu64, - &cdata[sizeof (rev)], - pkey_str, - rev.expiration.abs_value_us); - GNUNET_free (pkey_str); - return rev_str; - - } default: return NULL; } @@ -335,48 +311,6 @@ gns_string_to_value (void *cls, GNUNET_free (bval); return GNUNET_OK; } - case GNUNET_GNSRECORD_TYPE_REVERSE: - { - struct GNUNET_GNSRECORD_ReverseRecord *rev; - char known_by[253 + 1]; - struct GNUNET_TIME_Absolute expiration; - - /* TODO: From crypto_ecc.c - * Why is this not a constant??? - */ - size_t enclen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8; - if (enclen % 5 > 0) - enclen += 5 - enclen % 5; - enclen /= 5; /* 260/5 = 52 */ - char pkey_str[enclen + 1]; - - if (3 != SSCANF (s, - "%253s %52s %"SCNu64, - known_by, - pkey_str, - &expiration.abs_value_us)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _("Unable to parse REVERSE record string `%s'\n"), - s); - return GNUNET_SYSERR; - } - *data_size = sizeof (struct GNUNET_GNSRECORD_ReverseRecord) + strlen (known_by) + 1; - *data = rev = GNUNET_malloc (*data_size); - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_public_key_from_string (pkey_str, - strlen (pkey_str), - &rev->pkey)) - { - GNUNET_free (rev); - return GNUNET_SYSERR; - } - rev->expiration = expiration; - GNUNET_memcpy (&rev[1], - known_by, - strlen (known_by)); - return GNUNET_OK; - } default: return GNUNET_SYSERR; } @@ -397,7 +331,6 @@ static struct { { "VPN", GNUNET_GNSRECORD_TYPE_VPN }, { "GNS2DNS", GNUNET_GNSRECORD_TYPE_GNS2DNS }, { "BOX", GNUNET_GNSRECORD_TYPE_BOX }, - { "REVERSE", GNUNET_GNSRECORD_TYPE_REVERSE }, { NULL, UINT32_MAX } }; diff --git a/src/identity-attribute/Makefile.am b/src/identity-attribute/Makefile.am new file mode 100644 index 000000000..2c73a443e --- /dev/null +++ b/src/identity-attribute/Makefile.am @@ -0,0 +1,44 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +plugindir = $(libdir)/gnunet + +pkgcfgdir= $(pkgdatadir)/config.d/ + +libexecdir= $(pkglibdir)/libexec/ + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIBS = -lgcov +endif + +lib_LTLIBRARIES = \ + libgnunetidentityattribute.la + +libgnunetidentityattribute_la_SOURCES = \ + identity_attribute.c +libgnunetidentityattribute_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) +libgnunetidentityattribute_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +plugin_LTLIBRARIES = \ + libgnunet_plugin_identity_attribute_gnuid.la + + +libgnunet_plugin_identity_attribute_gnuid_la_SOURCES = \ + plugin_identity_attribute_gnuid.c +libgnunet_plugin_identity_attribute_gnuid_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LTLIBINTL) +libgnunet_plugin_identity_attribute_gnuid_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + diff --git a/src/identity-attribute/identity_attribute.c b/src/identity-attribute/identity_attribute.c new file mode 100644 index 000000000..cf50d058e --- /dev/null +++ b/src/identity-attribute/identity_attribute.c @@ -0,0 +1,421 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2015 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +/** + * @file identity-attribute/identity_attribute.c + * @brief helper library to manage identity attributes + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "identity_attribute.h" +#include "gnunet_identity_attribute_plugin.h" + +/** + * Handle for a plugin + */ +struct Plugin +{ + /** + * Name of the plugin + */ + char *library_name; + + /** + * Plugin API + */ + struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api; +}; + +/** + * Plugins + */ +static struct Plugin **attr_plugins; + +/** + * Number of plugins + */ +static unsigned int num_plugins; + +/** + * Init canary + */ +static int initialized; + +/** + * Add a plugin + */ +static void +add_plugin (void* cls, + const char *library_name, + void *lib_ret) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api = lib_ret; + struct Plugin *plugin; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Loading attribute plugin `%s'\n", + library_name); + plugin = GNUNET_new (struct Plugin); + plugin->api = api; + plugin->library_name = GNUNET_strdup (library_name); + GNUNET_array_append (attr_plugins, num_plugins, plugin); +} + +/** + * Load plugins + */ +static void +init() +{ + if (GNUNET_YES == initialized) + return; + initialized = GNUNET_YES; + GNUNET_PLUGIN_load_all ("libgnunet_plugin_identity_attribute_", NULL, + &add_plugin, NULL); +} + +/** + * Convert a type name to the corresponding number + * + * @param typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +uint32_t +GNUNET_IDENTITY_ATTRIBUTE_typename_to_number (const char *typename) +{ + unsigned int i; + struct Plugin *plugin; + uint32_t ret; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (UINT32_MAX != (ret = plugin->api->typename_to_number (plugin->api->cls, + typename))) + return ret; + } + return UINT32_MAX; +} + +/** + * Convert a type number to the corresponding type string + * + * @param type number of a type + * @return corresponding typestring, NULL on error + */ +const char* +GNUNET_IDENTITY_ATTRIBUTE_number_to_typename (uint32_t type) +{ + unsigned int i; + struct Plugin *plugin; + const char *ret; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (NULL != (ret = plugin->api->number_to_typename (plugin->api->cls, + type))) + return ret; + } + return NULL; +} + +/** + * Convert human-readable version of a 'claim' of an attribute to the binary + * representation + * + * @param type type of the claim + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +int +GNUNET_IDENTITY_ATTRIBUTE_string_to_value (uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + unsigned int i; + struct Plugin *plugin; + + init (); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (GNUNET_OK == plugin->api->string_to_value (plugin->api->cls, + type, + s, + data, + data_size)) + return GNUNET_OK; + } + return GNUNET_SYSERR; +} + +/** + * Convert the 'claim' of an attribute to a string + * + * @param type the type of attribute + * @param data claim in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the claim + */ +char * +GNUNET_IDENTITY_ATTRIBUTE_value_to_string (uint32_t type, + const void* data, + size_t data_size) +{ + unsigned int i; + struct Plugin *plugin; + char *ret; + + init(); + for (i = 0; i < num_plugins; i++) + { + plugin = attr_plugins[i]; + if (NULL != (ret = plugin->api->value_to_string (plugin->api->cls, + type, + data, + data_size))) + return ret; + } + return NULL; +} + +/** + * Create a new attribute. + * + * @param attr_name the attribute name + * @param type the attribute type + * @param data the attribute value + * @param data_size the attribute value size + * @return the new attribute + */ +struct GNUNET_IDENTITY_ATTRIBUTE_Claim * +GNUNET_IDENTITY_ATTRIBUTE_claim_new (const char* attr_name, + uint32_t type, + const void* data, + size_t data_size) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr; + char *write_ptr; + + attr = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_ATTRIBUTE_Claim) + + strlen (attr_name) + 1 + + data_size); + attr->type = type; + attr->data_size = data_size; + attr->version = 0; + write_ptr = (char*)&attr[1]; + GNUNET_memcpy (write_ptr, + attr_name, + strlen (attr_name) + 1); + attr->name = write_ptr; + write_ptr += strlen (attr->name) + 1; + GNUNET_memcpy (write_ptr, + data, + data_size); + attr->data = write_ptr; + return attr; +} + +size_t +GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + size_t len = 0; + for (le = attrs->list_head; NULL != le; le = le->next) + len += GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (le->claim); + return len; +} + +size_t +GNUNET_IDENTITY_ATTRIBUTE_list_serialize (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, + char *result) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + size_t len; + size_t total_len; + char* write_ptr; + + write_ptr = result; + total_len = 0; + for (le = attrs->list_head; NULL != le; le = le->next) + { + len = GNUNET_IDENTITY_ATTRIBUTE_serialize (le->claim, + write_ptr); + total_len += len; + write_ptr += len; + } + return total_len; +} + +struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList * +GNUNET_IDENTITY_ATTRIBUTE_list_deserialize (const char* data, + size_t data_size) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + size_t attr_len; + const char* read_ptr; + + if (data_size < sizeof (struct Attribute)) + return NULL; + + attrs = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); + read_ptr = data; + while (((data + data_size) - read_ptr) >= sizeof (struct Attribute)) + { + + le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_IDENTITY_ATTRIBUTE_deserialize (read_ptr, + data_size - (read_ptr - data)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deserialized attribute %s\n", le->claim->name); + GNUNET_CONTAINER_DLL_insert (attrs->list_head, + attrs->list_tail, + le); + attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (le->claim); + read_ptr += attr_len; + } + return attrs; +} + +struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList* +GNUNET_IDENTITY_ATTRIBUTE_list_dup (const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *result_le; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *result; + size_t len; + + result = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); + for (le = attrs->list_head; NULL != le; le = le->next) + { + result_le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); + len = sizeof (struct GNUNET_IDENTITY_ATTRIBUTE_Claim) + le->claim->data_size; + result_le->claim = GNUNET_malloc (len); + GNUNET_memcpy (result_le->claim, + le->claim, + len); + result_le->claim->name = (const char*)&result_le->claim[1]; + GNUNET_CONTAINER_DLL_insert (result->list_head, + result->list_tail, + result_le); + } + return result; +} + + +void +GNUNET_IDENTITY_ATTRIBUTE_list_destroy (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *tmp_le; + + for (le = attrs->list_head; NULL != le;) + { + GNUNET_free (le->claim); + tmp_le = le; + le = le->next; + GNUNET_free (tmp_le); + } + GNUNET_free (attrs); + +} + +size_t +GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) +{ + return sizeof (struct Attribute) + + strlen (attr->name) + + attr->data_size; +} + +size_t +GNUNET_IDENTITY_ATTRIBUTE_serialize (const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr, + char *result) +{ + size_t data_len_ser; + size_t name_len; + struct Attribute *attr_ser; + char* write_ptr; + + attr_ser = (struct Attribute*)result; + attr_ser->attribute_type = htons (attr->type); + attr_ser->attribute_version = htonl (attr->version); + name_len = strlen (attr->name); + attr_ser->name_len = htons (name_len); + write_ptr = (char*)&attr_ser[1]; + GNUNET_memcpy (write_ptr, attr->name, name_len); + write_ptr += name_len; + //TODO plugin-ize + //data_len_ser = plugin->serialize_attribute_value (attr, + // &attr_ser[1]); + data_len_ser = attr->data_size; + GNUNET_memcpy (write_ptr, attr->data, attr->data_size); + attr_ser->data_size = htons (data_len_ser); + + return sizeof (struct Attribute) + strlen (attr->name) + attr->data_size; +} + +struct GNUNET_IDENTITY_ATTRIBUTE_Claim * +GNUNET_IDENTITY_ATTRIBUTE_deserialize (const char* data, + size_t data_size) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr; + struct Attribute *attr_ser; + size_t data_len; + size_t name_len; + char* write_ptr; + + if (data_size < sizeof (struct Attribute)) + return NULL; + + attr_ser = (struct Attribute*)data; + data_len = ntohs (attr_ser->data_size); + name_len = ntohs (attr_ser->name_len); + attr = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_ATTRIBUTE_Claim) + + data_len + name_len + 1); + attr->type = ntohs (attr_ser->attribute_type); + attr->version = ntohl (attr_ser->attribute_version); + attr->data_size = ntohs (attr_ser->data_size); + + write_ptr = (char*)&attr[1]; + GNUNET_memcpy (write_ptr, + &attr_ser[1], + name_len); + write_ptr[name_len] = '\0'; + attr->name = write_ptr; + + write_ptr += name_len + 1; + GNUNET_memcpy (write_ptr, + (char*)&attr_ser[1] + name_len, + attr->data_size); + attr->data = write_ptr; + return attr; + +} + +/* end of identity_attribute.c */ diff --git a/src/identity-attribute/identity_attribute.h b/src/identity-attribute/identity_attribute.h new file mode 100644 index 000000000..8dfc17521 --- /dev/null +++ b/src/identity-attribute/identity_attribute.h @@ -0,0 +1,56 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/** + * @author Martin Schanzenbach + * @file identity-attribute/identity_attribute.h + * @brief GNUnet Identity attributes + * + */ +#ifndef IDENTITY_ATTRIBUTE_H +#define IDENTITY_ATTRIBUTE_H + +#include "gnunet_identity_provider_service.h" + +struct Attribute +{ + /** + * Attribute type + */ + uint32_t attribute_type; + + /** + * Attribute version + */ + uint32_t attribute_version; + + /** + * Name length + */ + uint32_t name_len; + + /** + * Data size + */ + uint32_t data_size; + + //followed by data_size Attribute value data +}; + +#endif diff --git a/src/identity-attribute/plugin_identity_attribute_gnuid.c b/src/identity-attribute/plugin_identity_attribute_gnuid.c new file mode 100644 index 000000000..006b45ea2 --- /dev/null +++ b/src/identity-attribute/plugin_identity_attribute_gnuid.c @@ -0,0 +1,184 @@ +/* + This file is part of GNUnet + Copyright (C) 2013, 2014, 2016 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file identity-attribute/plugin_identity_attribute_gnuid.c + * @brief identity attribute plugin to provide the API for fundamental + * attribute types. + * + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_identity_attribute_plugin.h" +#include <inttypes.h> + + +/** + * Convert the 'value' of an attribute to a string. + * + * @param cls closure, unused + * @param type type of the attribute + * @param data value in binary encoding + * @param data_size number of bytes in @a data + * @return NULL on error, otherwise human-readable representation of the value + */ +static char * +gnuid_value_to_string (void *cls, + uint32_t type, + const void *data, + size_t data_size) +{ + + switch (type) + { + case GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING: + return GNUNET_strndup (data, data_size); + default: + return NULL; + } +} + + +/** + * Convert human-readable version of a 'value' of an attribute to the binary + * representation. + * + * @param cls closure, unused + * @param type type of the attribute + * @param s human-readable string + * @param data set to value in binary encoding (will be allocated) + * @param data_size set to number of bytes in @a data + * @return #GNUNET_OK on success + */ +static int +gnuid_string_to_value (void *cls, + uint32_t type, + const char *s, + void **data, + size_t *data_size) +{ + if (NULL == s) + return GNUNET_SYSERR; + switch (type) + { + + case GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING: + *data = GNUNET_strdup (s); + *data_size = strlen (s); + return GNUNET_OK; + default: + return GNUNET_SYSERR; + } +} + + +/** + * Mapping of attribute type numbers to human-readable + * attribute type names. + */ +static struct { + const char *name; + uint32_t number; +} gnuid_name_map[] = { + { "STRING", GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING }, + { NULL, UINT32_MAX } +}; + + +/** + * Convert a type name to the corresponding number. + * + * @param cls closure, unused + * @param gnuid_typename name to convert + * @return corresponding number, UINT32_MAX on error + */ +static uint32_t +gnuid_typename_to_number (void *cls, + const char *gnuid_typename) +{ + unsigned int i; + + i=0; + while ( (NULL != gnuid_name_map[i].name) && + (0 != strcasecmp (gnuid_typename, + gnuid_name_map[i].name)) ) + i++; + return gnuid_name_map[i].number; +} + + +/** + * Convert a type number (i.e. 1) to the corresponding type string + * + * @param cls closure, unused + * @param type number of a type to convert + * @return corresponding typestring, NULL on error + */ +static const char * +gnuid_number_to_typename (void *cls, + uint32_t type) +{ + unsigned int i; + + i=0; + while ( (NULL != gnuid_name_map[i].name) && + (type != gnuid_name_map[i].number) ) + i++; + return gnuid_name_map[i].name; +} + + +/** + * Entry point for the plugin. + * + * @param cls NULL + * @return the exported block API + */ +void * +libgnunet_plugin_identity_attribute_gnuid_init (void *cls) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api; + + api = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions); + api->value_to_string = &gnuid_value_to_string; + api->string_to_value = &gnuid_string_to_value; + api->typename_to_number = &gnuid_typename_to_number; + api->number_to_typename = &gnuid_number_to_typename; + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the return value from #libgnunet_plugin_block_test_init() + * @return NULL + */ +void * +libgnunet_plugin_identity_attribute_gnuid_done (void *cls) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_PluginFunctions *api = cls; + + GNUNET_free (api); + return NULL; +} + +/* end of plugin_identity_attribute_type_gnuid.c */ diff --git a/src/identity-provider/Makefile.am b/src/identity-provider/Makefile.am index 0d8752c4c..adf6af3b3 100644 --- a/src/identity-provider/Makefile.am +++ b/src/identity-provider/Makefile.am @@ -12,6 +12,15 @@ if USE_COVERAGE XLIB = -lgcov endif +if HAVE_SQLITE +SQLITE_PLUGIN = libgnunet_plugin_identity_provider_sqlite.la +endif + +EXTRA_DIST = \ + test_idp_defaults.conf \ + test_idp.conf \ + $(check_SCRIPTS) + pkgcfgdir= $(pkgdatadir)/config.d/ libexecdir= $(pkglibdir)/libexec/ @@ -22,29 +31,51 @@ pkgcfg_DATA = \ lib_LTLIBRARIES = \ libgnunetidentityprovider.la plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_identity_provider.la + libgnunet_plugin_rest_identity_provider.la \ + libgnunet_plugin_gnsrecord_identity_provider.la \ + $(SQLITE_PLUGIN) bin_PROGRAMS = \ - gnunet-identity-token + gnunet-idp libexec_PROGRAMS = \ gnunet-service-identity-provider -EXTRA_DIST = \ - $(pkgcfg_DATA) +libgnunet_plugin_gnsrecord_identity_provider_la_SOURCES = \ + plugin_gnsrecord_identity_provider.c +libgnunet_plugin_gnsrecord_identity_provider_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(LTLIBINTL) +libgnunet_plugin_gnsrecord_identity_provider_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + +libgnunet_plugin_identity_provider_sqlite_la_SOURCES = \ + plugin_identity_provider_sqlite.c +libgnunet_plugin_identity_provider_sqlite_la_LIBADD = \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/sq/libgnunetsq.la \ + $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ + $(LTLIBINTL) +libgnunet_plugin_identity_provider_sqlite_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + gnunet_service_identity_provider_SOURCES = \ - gnunet-service-identity-provider.c \ - identity_token.c identity_token.h + gnunet-service-identity-provider.c gnunet_service_identity_provider_LDADD = \ $(top_builddir)/src/gnsrecord/libgnunetgnsrecord.la \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/identity/libgnunetidentity.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ + $(top_builddir)/src/abe/libgnunetabe.la \ + $(top_builddir)/src/credential/libgnunetcredential.la \ + $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ + libgnunetidentityprovider.la \ $(top_builddir)/src/gns/libgnunetgns.la \ - $(GN_LIBINTL) \ - -ljansson + $(GN_LIBINTL) libgnunetidentityprovider_la_SOURCES = \ identity_provider_api.c \ @@ -57,22 +88,37 @@ libgnunetidentityprovider_la_LDFLAGS = \ -version-info 0:0:0 libgnunet_plugin_rest_identity_provider_la_SOURCES = \ - plugin_rest_identity_provider.c + plugin_rest_identity_provider.c \ + jwt.c libgnunet_plugin_rest_identity_provider_la_LIBADD = \ $(top_builddir)/src/identity/libgnunetidentity.la \ libgnunetidentityprovider.la \ $(top_builddir)/src/rest/libgnunetrest.la \ $(top_builddir)/src/jsonapi/libgnunetjsonapi.la \ + $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ $(top_builddir)/src/namestore/libgnunetnamestore.la \ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ $(LTLIBINTL) -ljansson -lmicrohttpd libgnunet_plugin_rest_identity_provider_la_LDFLAGS = \ $(GN_PLUGIN_LDFLAGS) - -gnunet_identity_token_SOURCES = \ - gnunet-identity-token.c -gnunet_identity_token_LDADD = \ +gnunet_idp_SOURCES = \ + gnunet-idp.c +gnunet_idp_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ - -ljansson -lmicrohttpd \ + $(top_builddir)/src/namestore/libgnunetnamestore.la \ + libgnunetidentityprovider.la \ + $(top_builddir)/src/identity/libgnunetidentity.la \ + $(top_builddir)/src/identity-attribute/libgnunetidentityattribute.la \ $(GN_LIBINTL) + +check_SCRIPTS = \ + test_idp_attribute.sh \ + test_idp_issue.sh \ + test_idp_consume.sh \ + test_idp_revoke.sh + +if ENABLE_TEST_RUN + AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; + TESTS = $(check_SCRIPTS) +endif diff --git a/src/identity-provider/gnunet-identity-token.c b/src/identity-provider/gnunet-identity-token.c deleted file mode 100644 index 30b63bfc4..000000000 --- a/src/identity-provider/gnunet-identity-token.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ -/** - * @author Martin Schanzenbach - * @file src/identity-provider/gnunet-service-identity-provider.c - * @brief Identity Token Service - * - */ - -#include "platform.h" -#include "gnunet_util_lib.h" -#include <jansson.h> -#include "gnunet_signatures.h" - -/** - * The token - */ -static char* token; - -/** - * Weather to print the token - */ -static int print_token; - -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *c) -{ - char *payload; - char *header; - //Get token parts - const char *header_b64; - const char *payload_b64; - const char *signature_b32; - const char *keystring; - char *data; - json_t *payload_json; - json_t *keystring_json; - json_error_t error; - struct GNUNET_CRYPTO_EcdsaPublicKey key; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - struct GNUNET_CRYPTO_EcdsaSignature sig; - - if (NULL == token) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - _("Option `-t' is required\n")); - return; - } - header_b64 = strtok (token, "."); - payload_b64 = strtok (NULL, "."); - signature_b32 = strtok (NULL, "."); - if ( (NULL == header_b64) || - (NULL == payload_b64) || - (NULL == signature_b32) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, - _("Token `%s' is malformed\n"), - token); - GNUNET_free (token); - token = NULL; - return; - } - - //Decode payload - GNUNET_STRINGS_base64_decode (payload_b64, - strlen (payload_b64), - &payload); - //Decode header - GNUNET_STRINGS_base64_decode (header_b64, - strlen (header_b64), - &header); - - - GNUNET_asprintf(&data, - "%s,%s", - header_b64, - payload_b64); - char *val = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data)); - purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose*)val; - purpose->size = htonl(sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + strlen (data)); - purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN); - GNUNET_memcpy (&purpose[1], data, strlen(data)); - GNUNET_free (data); - GNUNET_free (token); - token = NULL; - - if (print_token) - printf ("Token:\nHeader:\t\t%s\nPayload:\t%s\n", - header, - payload); - GNUNET_free (header); - - payload_json = json_loads (payload, 0, &error); - GNUNET_free (payload); - - if ((NULL == payload_json) || (! json_is_object (payload_json)) ) - { - GNUNET_free (val); - return; - } - keystring_json = json_object_get (payload_json, "iss"); - if (! json_is_string (keystring_json)) - { - GNUNET_free (val); - return; - } - keystring = json_string_value (keystring_json); - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_public_key_from_string (keystring, - strlen (keystring), - &key)) - { - GNUNET_free (val); - return; - } - GNUNET_STRINGS_string_to_data (signature_b32, - strlen (signature_b32), - &sig, - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); - - if (print_token) - printf ("Signature:\t%s\n", - keystring); - - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_verify(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN, - purpose, - &sig, - &key)) - printf("Signature not OK!\n"); - else - printf("Signature OK!\n"); - GNUNET_free (val); - return; -} - - -int -main(int argc, char *const argv[]) -{ - struct GNUNET_GETOPT_CommandLineOption options[] = { - - GNUNET_GETOPT_option_string ('t', - "token", - NULL, - gettext_noop ("GNUid token"), - &token), - - GNUNET_GETOPT_option_flag ('p', - "print", - gettext_noop ("Print token contents"), - &print_token), - - GNUNET_GETOPT_OPTION_END - }; - return GNUNET_PROGRAM_run (argc, argv, "ct", - "ct", options, - &run, NULL); -} diff --git a/src/identity-provider/gnunet-idp.c b/src/identity-provider/gnunet-idp.c new file mode 100644 index 000000000..62f07842b --- /dev/null +++ b/src/identity-provider/gnunet-idp.c @@ -0,0 +1,439 @@ +/* + This file is part of GNUnet. + Copyright (C) 2012-2015 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ +/** + * @author Martin Schanzenbach + * @file src/identity-provider/gnunet-idp.c + * @brief Identity Provider utility + * + */ + +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_namestore_service.h" +#include "gnunet_identity_provider_service.h" +#include "gnunet_identity_service.h" +#include "gnunet_signatures.h" + +/** + * return value + */ +static int ret; + +/** + * List attribute flag + */ +static int list; + +/** + * Relying party + */ +static char* rp; + +/** + * The attribute + */ +static char* attr_name; + +/** + * Attribute value + */ +static char* attr_value; + +/** + * Attributes to issue + */ +static char* issue_attrs; + +/** + * Ticket to consume + */ +static char* consume_ticket; + +/** + * Attribute type + */ +static char* type_str; + +/** + * Ticket to revoke + */ +static char* revoke_ticket; + +/** + * Ego name + */ +static char* ego_name; + +/** + * Identity handle + */ +static struct GNUNET_IDENTITY_Handle *identity_handle; + +/** + * IdP handle + */ +static struct GNUNET_IDENTITY_PROVIDER_Handle *idp_handle; + +/** + * IdP operation + */ +static struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op; + +/** + * Attribute iterator + */ +static struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_iterator; + +/** + * Master ABE key + */ +static struct GNUNET_CRYPTO_AbeMasterKey *abe_key; + +/** + * ego private key + */ +static const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey; + +/** + * rp public key + */ +static struct GNUNET_CRYPTO_EcdsaPublicKey rp_key; + +/** + * Ticket to consume + */ +static struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; + +/** + * Attribute list + */ +static struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attr_list; + +static void +do_cleanup(void *cls) +{ + if (NULL != attr_iterator) + GNUNET_IDENTITY_PROVIDER_get_attributes_stop (attr_iterator); + if (NULL != idp_handle) + GNUNET_IDENTITY_PROVIDER_disconnect (idp_handle); + if (NULL != identity_handle) + GNUNET_IDENTITY_disconnect (identity_handle); + if (NULL != abe_key) + GNUNET_free (abe_key); + if (NULL != attr_list) + GNUNET_free (attr_list); +} + +static void +ticket_issue_cb (void* cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) +{ + char* ticket_str; + if (NULL != ticket) { + ticket_str = GNUNET_STRINGS_data_to_string_alloc (ticket, + sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); + printf("%s\n", + ticket_str); + GNUNET_free (ticket_str); + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +store_attr_cont (void *cls, + int32_t success, + const char*emsg) +{ + if (GNUNET_SYSERR == success) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "%s\n", emsg); + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +process_attrs (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) +{ + char *value_str; + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); + return; + } + if (NULL == attr) + { + ret = 1; + return; + } + value_str = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (attr->type, + attr->data, + attr->data_size); + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "%s: %s\n", attr->name, value_str); +} + + +static void +iter_error (void *cls) +{ + attr_iterator = NULL; + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to iterate over attributes\n"); + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +process_rvk (void *cls, int success, const char* msg) +{ + if (GNUNET_OK != success) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "Revocation failed.\n"); + ret = 1; + } + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); +} + +static void +iter_finished (void *cls) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_Claim *claim; + char *data; + size_t data_size; + int type; + + attr_iterator = NULL; + if (list) + { + GNUNET_SCHEDULER_add_now (&do_cleanup, NULL); + return; + } + + if (issue_attrs) + { + idp_op = GNUNET_IDENTITY_PROVIDER_ticket_issue (idp_handle, + pkey, + &rp_key, + attr_list, + &ticket_issue_cb, + NULL); + return; + } + if (consume_ticket) + { + idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (idp_handle, + pkey, + &ticket, + &process_attrs, + NULL); + return; + } + if (revoke_ticket) + { + idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (idp_handle, + pkey, + &ticket, + &process_rvk, + NULL); + return; + } + if (NULL == type_str) + type = GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING; + else + type = GNUNET_IDENTITY_ATTRIBUTE_typename_to_number (type_str); + + GNUNET_assert (GNUNET_SYSERR != GNUNET_IDENTITY_ATTRIBUTE_string_to_value (type, + attr_value, + (void**)&data, + &data_size)); + claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr_name, + type, + data, + data_size); + idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (idp_handle, + pkey, + claim, + &store_attr_cont, + NULL); + + +} + +static void +iter_cb (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + char *attrs_tmp; + char *attr_str; + + if (issue_attrs) + { + attrs_tmp = GNUNET_strdup (issue_attrs); + attr_str = strtok (attrs_tmp, ","); + while (NULL != attr_str) { + if (0 != strcmp (attr_str, attr->name)) { + attr_str = strtok (NULL, ","); + continue; + } + le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); + le->claim = GNUNET_IDENTITY_ATTRIBUTE_claim_new (attr->name, + attr->type, + attr->data, + attr->data_size); + GNUNET_CONTAINER_DLL_insert (attr_list->list_head, + attr_list->list_tail, + le); + break; + } + GNUNET_free (attrs_tmp); + } else if (list) { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + "%s: %s\n", attr->name, (char*)attr->data); + } + GNUNET_IDENTITY_PROVIDER_get_attributes_next (attr_iterator); +} + +static void +ego_cb (void *cls, + struct GNUNET_IDENTITY_Ego *ego, + void **ctx, + const char *name) +{ + if (NULL == name) + return; + if (0 != strcmp (name, ego_name)) + return; + pkey = GNUNET_IDENTITY_ego_get_private_key (ego); + + if (NULL != rp) + GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, + strlen (rp), + &rp_key); + if (NULL != consume_ticket) + GNUNET_STRINGS_string_to_data (consume_ticket, + strlen (consume_ticket), + &ticket, + sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); + if (NULL != revoke_ticket) + GNUNET_STRINGS_string_to_data (revoke_ticket, + strlen (revoke_ticket), + &ticket, + sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); + + + attr_list = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); + + attr_iterator = GNUNET_IDENTITY_PROVIDER_get_attributes_start (idp_handle, + pkey, + &iter_error, + NULL, + &iter_cb, + NULL, + &iter_finished, + NULL); + + +} + +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + ret = 0; + if (NULL == ego_name) + { + GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, + _("Ego is required\n")); + return; + } + + idp_handle = GNUNET_IDENTITY_PROVIDER_connect (c); + //Get Ego + identity_handle = GNUNET_IDENTITY_connect (c, + &ego_cb, + NULL); + + +} + + +int +main(int argc, char *const argv[]) +{ + struct GNUNET_GETOPT_CommandLineOption options[] = { + + GNUNET_GETOPT_option_string ('a', + "add", + NULL, + gettext_noop ("Add attribute"), + &attr_name), + + GNUNET_GETOPT_option_string ('V', + "value", + NULL, + gettext_noop ("Attribute value"), + &attr_value), + GNUNET_GETOPT_option_string ('e', + "ego", + NULL, + gettext_noop ("Ego"), + &ego_name), + GNUNET_GETOPT_option_string ('r', + "rp", + NULL, + gettext_noop ("Audience (relying party)"), + &rp), + GNUNET_GETOPT_option_flag ('D', + "dump", + gettext_noop ("List attributes for Ego"), + &list), + GNUNET_GETOPT_option_string ('i', + "issue", + NULL, + gettext_noop ("Issue a ticket"), + &issue_attrs), + GNUNET_GETOPT_option_string ('C', + "consume", + NULL, + gettext_noop ("Consume a ticket"), + &consume_ticket), + GNUNET_GETOPT_option_string ('R', + "revoke", + NULL, + gettext_noop ("Revoke a ticket"), + &revoke_ticket), + GNUNET_GETOPT_option_string ('t', + "type", + NULL, + gettext_noop ("Type of attribute"), + &type_str), + GNUNET_GETOPT_OPTION_END + }; + GNUNET_PROGRAM_run (argc, argv, "ct", + "ct", options, + &run, NULL); + return ret; +} diff --git a/src/identity-provider/gnunet-service-identity-provider.c b/src/identity-provider/gnunet-service-identity-provider.c index 53fd02c9f..4e1de36cd 100644 --- a/src/identity-provider/gnunet-service-identity-provider.c +++ b/src/identity-provider/gnunet-service-identity-provider.c @@ -30,12 +30,14 @@ #include "gnunet_identity_service.h" #include "gnunet_gnsrecord_lib.h" #include "gnunet_namestore_service.h" +#include "gnunet_abe_lib.h" +#include "gnunet_credential_service.h" #include "gnunet_statistics_service.h" #include "gnunet_gns_service.h" +#include "gnunet_identity_provider_plugin.h" +#include "gnunet_identity_attribute_lib.h" #include "gnunet_signatures.h" #include "identity_provider.h" -#include "identity_token.h" -#include <inttypes.h> /** * First pass state @@ -58,24 +60,19 @@ #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS /** - * Service state (to detect initial update pass) - */ -static int state; - -/** - * Head of ego entry DLL + * Identity handle */ -static struct EgoEntry *ego_head; +static struct GNUNET_IDENTITY_Handle *identity_handle; /** - * Tail of ego entry DLL + * Database handle */ -static struct EgoEntry *ego_tail; +static struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *TKT_database; /** - * Identity handle + * Name of DB plugin */ -static struct GNUNET_IDENTITY_Handle *identity_handle; +static char *db_lib_name; /** * Token expiration interval @@ -93,6 +90,16 @@ static struct GNUNET_NAMESTORE_Handle *ns_handle; static struct GNUNET_GNS_Handle *gns_handle; /** + * Credential handle + */ +static struct GNUNET_CREDENTIAL_Handle *credential_handle; + +/** + * Stats handle + */ +static struct GNUNET_STATISTICS_Handle *stats_handle; + +/** * Namestore qe */ static struct GNUNET_NAMESTORE_QueueEntry *ns_qe; @@ -112,11 +119,6 @@ static struct GNUNET_SCHEDULER_Task *timeout_task; */ static struct GNUNET_SCHEDULER_Task *update_task; -/** - * Timeout for next update pass - */ -static struct GNUNET_TIME_Relative min_rel_exp; - /** * Currently processed token @@ -134,43 +136,260 @@ static char* label; static char* scopes; /** - * Expiration for processed token + * Handle to the statistics service. */ -static uint64_t rd_exp; +static struct GNUNET_STATISTICS_Handle *stats; /** - * ECDHE Privkey for processed token metadata + * Our configuration. */ -static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey; +static const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Handle to the statistics service. + * An idp client */ -static struct GNUNET_STATISTICS_Handle *stats; +struct IdpClient; /** - * Our configuration. + * A ticket iteration operation. */ -static const struct GNUNET_CONFIGURATION_Handle *cfg; +struct TicketIteration +{ + /** + * DLL + */ + struct TicketIteration *next; + + /** + * DLL + */ + struct TicketIteration *prev; + + /** + * Client which intiated this zone iteration + */ + struct IdpClient *client; + /** + * Key of the identity we are iterating over. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; -struct ExchangeHandle + /** + * Identity is audience + */ + uint32_t is_audience; + + /** + * The operation id fot the iteration in the response for the client + */ + uint32_t r_id; + + /** + * Offset of the iteration used to address next result of the + * iteration in the store + * + * Initialy set to 0 in handle_iteration_start + * Incremented with by every call to handle_iteration_next + */ + uint32_t offset; + +}; + + + +/** + * Callback after an ABE bootstrap + * + * @param cls closure + * @param abe_key the ABE key that exists or was created + */ +typedef void +(*AbeBootstrapResult) (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key); + + +struct AbeBootstrapHandle { + /** + * Function to call when finished + */ + AbeBootstrapResult proc; /** - * Client connection + * Callback closure + */ + char *proc_cls; + + /** + * Key of the zone we are iterating over. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Namestore Queue Entry + */ + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + + /** + * The issuer egos ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; +}; + +/** + * An attribute iteration operation. + */ +struct AttributeIterator +{ + /** + * Next element in the DLL + */ + struct AttributeIterator *next; + + /** + * Previous element in the DLL + */ + struct AttributeIterator *prev; + + /** + * IDP client which intiated this zone iteration + */ + struct IdpClient *client; + + /** + * Key of the zone we are iterating over. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * The issuer egos ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; + + /** + * Namestore iterator + */ + struct GNUNET_NAMESTORE_ZoneIterator *ns_it; + + /** + * The operation id fot the zone iteration in the response for the client + */ + uint32_t request_id; + +}; + + + +/** + * An idp client + */ +struct IdpClient +{ + + /** + * The client */ struct GNUNET_SERVICE_Client *client; /** - * Ticket + * Message queue for transmission to @e client + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Head of the DLL of + * Attribute iteration operations in + * progress initiated by this client + */ + struct AttributeIterator *op_head; + + /** + * Tail of the DLL of + * Attribute iteration operations + * in progress initiated by this client + */ + struct AttributeIterator *op_tail; + + /** + * Head of DLL of ticket iteration ops + */ + struct TicketIteration *ticket_iter_head; + + /** + * Tail of DLL of ticket iteration ops + */ + struct TicketIteration *ticket_iter_tail; + + + /** + * Head of DLL of ticket revocation ops + */ + struct TicketRevocationHandle *revocation_list_head; + + /** + * Tail of DLL of ticket revocation ops + */ + struct TicketRevocationHandle *revocation_list_tail; +}; + + + +struct AttributeStoreHandle +{ + + /** + * Client connection + */ + struct IdpClient *client; + + /** + * Identity + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * Identity pubkey + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey; + + /** + * The issuer egos ABE master key + */ + struct GNUNET_ABE_AbeMasterKey *abe_key; + + /** + * QueueEntry + */ + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + + /** + * The attribute to store + */ + struct GNUNET_IDENTITY_ATTRIBUTE_Claim *claim; + + /** + * request id + */ + uint32_t r_id; +}; + + +/* Prototype */ +struct ParallelLookup; + +struct ConsumeTicketHandle +{ + + /** + * Client connection */ - struct TokenTicket *ticket; + struct IdpClient *client; /** - * Token returned + * Ticket */ - struct IdentityToken *token; + struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; /** * LookupRequest @@ -180,86 +399,173 @@ struct ExchangeHandle /** * Audience Key */ - struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey; + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; /** - * Label to return + * Audience Key */ - char *label; + struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub; /** + * Lookup DLL + */ + struct ParallelLookup *parallel_lookups_head; + + /** + * Lookup DLL + */ + struct ParallelLookup *parallel_lookups_tail; + + /** + * Kill task + */ + struct GNUNET_SCHEDULER_Task *kill_task; + + /** + * The ABE key + */ + struct GNUNET_ABE_AbeKey *key; + + /** + * Attributes + */ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; + + /** + * Lookup time + */ + struct GNUNET_TIME_Absolute lookup_start_time; + + /** * request id */ uint32_t r_id; }; -struct IssueHandle +/** + * Handle for a parallel GNS lookup job + */ +struct ParallelLookup { + /* DLL */ + struct ParallelLookup *next; + + /* DLL */ + struct ParallelLookup *prev; + + /* The GNS request */ + struct GNUNET_GNS_LookupRequest *lookup_request; + + /* The handle the return to */ + struct ConsumeTicketHandle *handle; + + /** + * Lookup time + */ + struct GNUNET_TIME_Absolute lookup_start_time; + + /* The label to look up */ + char *label; +}; + +/** + * Ticket revocation request handle + */ +struct TicketRevocationHandle +{ + /** + * DLL + */ + struct TicketRevocationHandle *next; + + /** + * DLL + */ + struct TicketRevocationHandle *prev; /** * Client connection */ - struct GNUNET_SERVICE_Client *client; + struct IdpClient *client; + + /** + * Attributes to reissue + */ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; + + /** + * Attributes to revoke + */ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *rvk_attrs; /** * Issuer Key */ - struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key; + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; /** - * Issue pubkey + * Ticket to issue */ - struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey; + struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; /** - * Audience Key + * QueueEntry */ - struct GNUNET_CRYPTO_EcdsaPublicKey aud_key; + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; /** - * Expiration + * Namestore iterator */ - struct GNUNET_TIME_Absolute expiration; + struct GNUNET_NAMESTORE_ZoneIterator *ns_it; /** - * Scopes + * The ABE master key */ - char *scopes; + struct GNUNET_ABE_AbeMasterKey *abe_key; /** - * nonce + * Offset */ - uint64_t nonce; + uint32_t offset; /** - * NS iterator + * request id */ - struct GNUNET_NAMESTORE_ZoneIterator *ns_it; + uint32_t r_id; +}; + + + +/** + * Ticket issue request handle + */ +struct TicketIssueHandle +{ /** - * Attribute map + * Client connection */ - struct GNUNET_CONTAINER_MultiHashMap *attr_map; + struct IdpClient *client; /** - * Token + * Attributes to issue */ - struct IdentityToken *token; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; /** - * Ticket + * Issuer Key */ - struct TokenTicket *ticket; + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; /** - * QueueEntry + * Ticket to issue */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; /** - * The label the token is stored under + * QueueEntry */ - char *label; + struct GNUNET_NAMESTORE_QueueEntry *ns_qe; /** * request id @@ -267,6 +573,7 @@ struct IssueHandle uint32_t r_id; }; + /** * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format * @@ -293,1303 +600,1774 @@ struct EgoEntry */ struct GNUNET_CONTAINER_MultiHashMap *attr_map; - /** - * Attributes are old and should be updated if GNUNET_YES - */ - int attributes_dirty; }; /** - * Continuation for token store call + * Cleanup task + */ +static void +cleanup() +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Cleaning up\n"); + if (NULL != stats) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + stats = NULL; + } + GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, + TKT_database)); + GNUNET_free (db_lib_name); + db_lib_name = NULL; + if (NULL != timeout_task) + GNUNET_SCHEDULER_cancel (timeout_task); + if (NULL != update_task) + GNUNET_SCHEDULER_cancel (update_task); + if (NULL != identity_handle) + GNUNET_IDENTITY_disconnect (identity_handle); + if (NULL != gns_handle) + GNUNET_GNS_disconnect (gns_handle); + if (NULL != credential_handle) + GNUNET_CREDENTIAL_disconnect (credential_handle); + if (NULL != ns_it) + GNUNET_NAMESTORE_zone_iteration_stop (ns_it); + if (NULL != ns_qe) + GNUNET_NAMESTORE_cancel (ns_qe); + if (NULL != ns_handle) + GNUNET_NAMESTORE_disconnect (ns_handle); + if (NULL != stats_handle) + GNUNET_STATISTICS_destroy (stats_handle, GNUNET_NO); + GNUNET_free_non_null (token); + GNUNET_free_non_null (label); + +} + +/** + * Shutdown task * * @param cls NULL - * @param success error code - * @param emsg error message */ static void -store_token_cont (void *cls, - int32_t success, - const char *emsg) +do_shutdown (void *cls) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Shutting down...\n"); + cleanup(); +} + +/** + * Finished storing newly bootstrapped ABE key + */ +static void +bootstrap_store_cont (void *cls, + int32_t success, + const char *emsg) { - ns_qe = NULL; + struct AbeBootstrapHandle *abh = cls; if (GNUNET_SYSERR == success) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to update token: %s\n", + "Failed to bootstrap ABE master %s\n", emsg); + abh->proc (abh->proc_cls, NULL); + GNUNET_free (abh->abe_key); + GNUNET_free (abh); return; } - GNUNET_NAMESTORE_zone_iterator_next (ns_it); + abh->proc (abh->proc_cls, abh->abe_key); + GNUNET_free (abh); } - /** - * This function updates the old token with new attributes, - * removes deleted attributes and expiration times. - * - * @param cls the ego entry + * Generates and stores a new ABE key */ static void -handle_token_update (void *cls) +bootstrap_store_task (void *cls) { - char *token_metadata; - char *write_ptr; - char *enc_token_str; - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey; - struct EgoEntry *ego_entry = cls; - struct GNUNET_GNSRECORD_Data token_record[2]; - struct GNUNET_HashCode key_hash; - struct GNUNET_TIME_Relative token_rel_exp; - struct GNUNET_TIME_Relative token_ttl; - struct GNUNET_TIME_Absolute token_exp; - struct GNUNET_TIME_Absolute token_nbf; - struct GNUNET_TIME_Absolute new_exp; - struct GNUNET_TIME_Absolute new_iat; - struct GNUNET_TIME_Absolute new_nbf; - struct IdentityToken *new_token; - struct TokenAttr *cur_value; - struct TokenAttr *attr; - size_t token_metadata_len; - - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, - &pub_key); - - //Note: We need the token expiration time here. Not the record expiration - //time. - //There are two types of tokens: Token that expire on GNS level with - //an absolute expiration time. Those are basically tokens that will - //be automatically revoked on (record)expiration. - //Tokens stored with relative expiration times will expire on the token level (token expiration) - //but this service will reissue new tokens that can be retrieved from GNS - //automatically. - - for (attr = token->attr_head; NULL != attr; attr = attr->next) - { - if (0 == strcmp (attr->name, "exp")) - { - GNUNET_assert (1 == sscanf (attr->val_head->value, - "%"SCNu64, - &token_exp.abs_value_us)); - } else if (0 == strcmp (attr->name, "nbf")) { - GNUNET_assert (1 == sscanf (attr->val_head->value, - "%"SCNu64, - &token_nbf.abs_value_us)); - } - } - token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp); - - token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp); - if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us) - { - //This token is not yet expired! Save and skip - if (min_rel_exp.rel_value_us > token_ttl.rel_value_us) - { - min_rel_exp = token_ttl; - } - GNUNET_free (token); - token = NULL; - GNUNET_free (label); - label = NULL; - GNUNET_free (scopes); - scopes = NULL; - GNUNET_NAMESTORE_zone_iterator_next (ns_it); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Token is expired. Create a new one\n"); - new_token = token_create (&pub_key, - &token->aud_key); - new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp); - new_nbf = GNUNET_TIME_absolute_get (); - new_iat = new_nbf; - for (attr = token->attr_head; NULL != attr; attr = attr->next) - { - if (0 == strcmp (attr->name, "exp")) - { - token_add_attr_int (new_token, attr->name, new_exp.abs_value_us); - } - else if (0 == strcmp (attr->name, "nbf")) - { - token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us); - } - else if (0 == strcmp (attr->name, "iat")) - { - token_add_attr_int (new_token, attr->name, new_iat.abs_value_us); - } - else if ((0 == strcmp (attr->name, "iss")) - || (0 == strcmp (attr->name, "aud"))) - { - //Omit - } - else if (0 == strcmp (attr->name, "sub")) - { - token_add_attr (new_token, - attr->name, - attr->val_head->value); - } - else - { - GNUNET_CRYPTO_hash (attr->name, - strlen (attr->name), - &key_hash); - //Check if attr still exists. omit of not - if (GNUNET_NO != - GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map, - &key_hash)) - { - cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map, - &key_hash); - GNUNET_assert (NULL != cur_value); - GNUNET_CONTAINER_DLL_insert (new_token->attr_head, - new_token->attr_tail, - cur_value); - } - } - } + struct AbeBootstrapHandle *abh = cls; + struct GNUNET_GNSRECORD_Data rd[1]; + char *key; + + rd[0].data_size = GNUNET_ABE_cpabe_serialize_master_key (abh->abe_key, + (void**)&key); + rd[0].data = key; + rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER; + rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE; + rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane? + abh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &abh->identity, + "+", + 1, + rd, + &bootstrap_store_cont, + abh); + GNUNET_free (key); +} - // reassemble and set - GNUNET_assert (token_serialize (new_token, - priv_key, - &new_ecdhe_privkey, - &enc_token_str)); - - token_record[0].data = enc_token_str; - token_record[0].data_size = strlen (enc_token_str) + 1; - token_record[0].expiration_time = rd_exp; //Old expiration time - token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN; - token_record[0].flags = GNUNET_GNSRECORD_RF_NONE; - - //Meta - token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey) - + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) - + strlen (scopes) + 1; //With 0-Terminator - token_metadata = GNUNET_malloc (token_metadata_len); - write_ptr = token_metadata; - GNUNET_memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); - write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey); - GNUNET_memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey); - GNUNET_memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator; - - token_record[1].data = token_metadata; - token_record[1].data_size = token_metadata_len; - token_record[1].expiration_time = rd_exp; - token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA; - token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE; - - ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - priv_key, - label, - 2, - token_record, - &store_token_cont, - ego_entry); - token_destroy (new_token); - token_destroy (token); - GNUNET_free (new_ecdhe_privkey); - GNUNET_free (enc_token_str); - token = NULL; - GNUNET_free (label); - label = NULL; - GNUNET_free (scopes); - scopes = NULL; +/** + * Error checking for ABE master + */ +static void +bootstrap_abe_error (void *cls) +{ + struct AbeBootstrapHandle *abh = cls; + GNUNET_free (abh); + abh->proc (abh->proc_cls, NULL); + GNUNET_free (abh); } +/** + * Handle ABE lookup in namestore + */ static void -update_identities(void *cls); +bootstrap_abe_result (void *cls, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, + const char *label, + unsigned int rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct AbeBootstrapHandle *abh = cls; + struct GNUNET_ABE_AbeMasterKey *abe_key; + + for (uint32_t i=0;i<rd_count;i++) { + if (GNUNET_GNSRECORD_TYPE_ABE_MASTER != rd[i].record_type) + continue; + abe_key = GNUNET_ABE_cpabe_deserialize_master_key (rd[i].data, + rd[i].data_size); + abh->proc (abh->proc_cls, abe_key); + GNUNET_free (abh); + return; + } + //No ABE master found, bootstrapping... + abh->abe_key = GNUNET_ABE_cpabe_create_master_key (); + GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh); +} /** - * - * Cleanup attr_map - * - * @param cls NULL - * @param key the key - * @param value the json_t attribute value - * @return #GNUNET_YES + * Bootstrap ABE master if it does not yet exists. + * Will call the AbeBootstrapResult processor when done. + * will always recreate the ABE key of GNUNET_YES == recreate */ -static int -clear_ego_attrs (void *cls, - const struct GNUNET_HashCode *key, - void *value) -{ - struct TokenAttr *attr = value; - struct TokenAttrValue *val; - struct TokenAttrValue *tmp_val; - for (val = attr->val_head; NULL != val;) +static void +bootstrap_abe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + AbeBootstrapResult proc, + void* cls, + int recreate) +{ + struct AbeBootstrapHandle *abh; + + abh = GNUNET_new (struct AbeBootstrapHandle); + abh->proc = proc; + abh->proc_cls = cls; + abh->identity = *identity; + if (GNUNET_YES == recreate) { - tmp_val = val->next; - GNUNET_CONTAINER_DLL_remove (attr->val_head, - attr->val_tail, - val); - GNUNET_free (val->value); - GNUNET_free (val); - val = tmp_val; + abh->abe_key = GNUNET_ABE_cpabe_create_master_key (); + GNUNET_SCHEDULER_add_now (&bootstrap_store_task, abh); + } else { + abh->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle, + identity, + "+", + &bootstrap_abe_error, + abh, + &bootstrap_abe_result, + abh); } - GNUNET_free (attr->name); - GNUNET_free (attr); - - return GNUNET_YES; } -static void -token_collect_error_cb (void *cls) -{ - struct EgoEntry *ego_entry = cls; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - ">>> Updating Ego failed!\n"); - //Clear attribute map for ego - GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map, - &clear_ego_attrs, - ego_entry); - GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map); - update_task = GNUNET_SCHEDULER_add_now (&update_identities, - ego_entry->next); +static int +create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash, + struct GNUNET_CRYPTO_SymmetricSessionKey *skey, + struct GNUNET_CRYPTO_SymmetricInitializationVector *iv) +{ + struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str; + + GNUNET_CRYPTO_hash_to_enc (new_key_hash, + &new_key_hash_str); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str); + static const char ctx_key[] = "gnuid-aes-ctx-key"; + GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), + new_key_hash, sizeof (struct GNUNET_HashCode), + ctx_key, strlen (ctx_key), + NULL, 0); + static const char ctx_iv[] = "gnuid-aes-ctx-iv"; + GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector), + new_key_hash, sizeof (struct GNUNET_HashCode), + ctx_iv, strlen (ctx_iv), + NULL, 0); + return GNUNET_OK; +} +static void +cleanup_ticket_issue_handle (struct TicketIssueHandle *handle) +{ + if (NULL != handle->attrs) + GNUNET_IDENTITY_ATTRIBUTE_list_destroy (handle->attrs); + if (NULL != handle->ns_qe) + GNUNET_NAMESTORE_cancel (handle->ns_qe); + GNUNET_free (handle); } static void -token_collect_finished_cb (void *cls) +send_ticket_result (struct IdpClient *client, + uint32_t r_id, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) { - struct EgoEntry *ego_entry = cls; + struct TicketResultMessage *irm; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket_buf; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - ">>> Updating Ego finished\n"); - //Clear attribute map for ego - GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map, - &clear_ego_attrs, - ego_entry); - GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map); - update_task = GNUNET_SCHEDULER_add_now (&update_identities, - ego_entry->next); -} + /* store ticket in DB */ + if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls, + ticket, + attrs)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to store ticket after issue\n"); + GNUNET_break (0); + } + env = GNUNET_MQ_msg_extra (irm, + sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket), + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT); + ticket_buf = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&irm[1]; + *ticket_buf = *ticket; + irm->id = htonl (r_id); + GNUNET_MQ_send (client->mq, + env); +} -/** - * - * Update all ID_TOKEN records for an identity and store them - * - * @param cls the identity entry - * @param zone the identity - * @param lbl the name of the record - * @param rd_count number of records - * @param rd record data - */ static void -token_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *lbl, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct EgoEntry *ego_entry = cls; - const struct GNUNET_GNSRECORD_Data *token_record; - const struct GNUNET_GNSRECORD_Data *token_metadata_record; - struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key; - struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key; - - //There should be only a single record for a token under a label - if (2 != rd_count) +store_ticket_issue_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct TicketIssueHandle *handle = cls; + + handle->ns_qe = NULL; + if (GNUNET_SYSERR == success) { - GNUNET_NAMESTORE_zone_iterator_next (ns_it); + cleanup_ticket_issue_handle (handle); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", + "Unknown Error\n"); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); return; } + send_ticket_result (handle->client, + handle->r_id, + &handle->ticket, + handle->attrs); + cleanup_ticket_issue_handle (handle); +} - if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA) - { - token_metadata_record = &rd[0]; - token_record = &rd[1]; + + +int +serialize_abe_keyinfo2 (const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_ABE_AbeKey *rp_key, + struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey, + char **result) +{ + struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + char *enc_keyinfo; + char *serialized_key; + char *buf; + char *write_ptr; + char attrs_str_len; + ssize_t size; + + struct GNUNET_CRYPTO_SymmetricSessionKey skey; + struct GNUNET_CRYPTO_SymmetricInitializationVector iv; + struct GNUNET_HashCode new_key_hash; + ssize_t enc_size; + + size = GNUNET_ABE_cpabe_serialize_key (rp_key, + (void**)&serialized_key); + attrs_str_len = 0; + for (le = attrs->list_head; NULL != le; le = le->next) { + attrs_str_len += strlen (le->claim->name) + 1; } - else - { - token_record = &rd[0]; - token_metadata_record = &rd[1]; + buf = GNUNET_malloc (attrs_str_len + size); + write_ptr = buf; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Writing attributes\n"); + for (le = attrs->list_head; NULL != le; le = le->next) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s\n", le->claim->name); + + + GNUNET_memcpy (write_ptr, + le->claim->name, + strlen (le->claim->name)); + write_ptr[strlen (le->claim->name)] = ','; + write_ptr += strlen (le->claim->name) + 1; } - if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA) - { - GNUNET_NAMESTORE_zone_iterator_next (ns_it); - return; + write_ptr--; + write_ptr[0] = '\0'; //replace last , with a 0-terminator + write_ptr++; + GNUNET_memcpy (write_ptr, + serialized_key, + size); + GNUNET_free (serialized_key); + // ECDH keypair E = eG + *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create(); + GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey, + &ecdh_pubkey); + enc_keyinfo = GNUNET_malloc (size + attrs_str_len); + // Derived key K = H(eB) + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey, + &ticket->audience, + &new_key_hash)); + create_sym_key_from_ecdh(&new_key_hash, &skey, &iv); + enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf, + size + attrs_str_len, + &skey, &iv, + enc_keyinfo); + *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+ + enc_size); + GNUNET_memcpy (*result, + &ecdh_pubkey, + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), + enc_keyinfo, + enc_size); + GNUNET_free (enc_keyinfo); + GNUNET_free (buf); + return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size; +} + + + +static void +issue_ticket_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + struct TicketIssueHandle *ih = cls; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; + struct GNUNET_GNSRECORD_Data code_record[1]; + struct GNUNET_ABE_AbeKey *rp_key; + char *code_record_data; + char **attrs; + char *label; + char *policy; + int attrs_len; + uint32_t i; + size_t code_record_len; + + //Create new ABE key for RP + attrs_len = 0; + for (le = ih->attrs->list_head; NULL != le; le = le->next) + attrs_len++; + attrs = GNUNET_malloc ((attrs_len + 1)*sizeof (char*)); + i = 0; + for (le = ih->attrs->list_head; NULL != le; le = le->next) { + GNUNET_asprintf (&policy, "%s_%lu", + le->claim->name, + le->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Adding attribute to key: %s\n", + policy); + attrs[i] = policy; + i++; } - if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN) + attrs[i] = NULL; + rp_key = GNUNET_ABE_cpabe_create_key (abe_key, + attrs); + + //TODO review this wireformat + code_record_len = serialize_abe_keyinfo2 (&ih->ticket, + ih->attrs, + rp_key, + &ecdhe_privkey, + &code_record_data); + code_record[0].data = code_record_data; + code_record[0].data_size = code_record_len; + code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us; + code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY; + code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + + label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, + sizeof (uint64_t)); + //Publish record + ih->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &ih->identity, + label, + 1, + code_record, + &store_ticket_issue_cont, + ih); + //for (; i > 0; i--) + // GNUNET_free (attrs[i-1]); + GNUNET_free (ecdhe_privkey); + GNUNET_free (label); + GNUNET_free (attrs); + GNUNET_free (code_record_data); + GNUNET_ABE_cpabe_delete_key (rp_key, + GNUNET_YES); + GNUNET_ABE_cpabe_delete_master_key (abe_key); +} + + +static int +check_issue_ticket_message(void *cls, + const struct IssueTicketMessage *im) +{ + uint16_t size; + + size = ntohs (im->header.size); + if (size <= sizeof (struct IssueTicketMessage)) { - GNUNET_NAMESTORE_zone_iterator_next (ns_it); - return; + GNUNET_break (0); + return GNUNET_SYSERR; } + return GNUNET_OK; +} - //Get metadata and decrypt token - priv_key = (struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data; - ecdhe_privkey = *priv_key; - aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&priv_key[1]; - scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - token_parse2 (token_record->data, - &ecdhe_privkey, - aud_key, - &token); +static void +handle_issue_ticket_message (void *cls, + const struct IssueTicketMessage *im) +{ + struct TicketIssueHandle *ih; + struct IdpClient *idp = cls; + size_t attrs_len; + + ih = GNUNET_new (struct TicketIssueHandle); + attrs_len = ntohs (im->attr_len); + ih->attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize ((char*)&im[1], attrs_len); + ih->r_id = ntohl (im->id); + ih->client = idp; + ih->identity = im->identity; + GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity, + &ih->ticket.identity); + ih->ticket.audience = im->rp; + ih->ticket.rnd = + GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, + UINT64_MAX); + bootstrap_abe (&ih->identity, &issue_ticket_after_abe_bootstrap, ih, GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); - label = GNUNET_strdup (lbl); - rd_exp = token_record->expiration_time; +} - GNUNET_SCHEDULER_add_now (&handle_token_update, - ego_entry); +/********************************************************** + * Revocation + **********************************************************/ + +/** + * Cleanup revoke handle + * + * @param rh the ticket revocation handle + */ +static void +cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh) +{ + if (NULL != rh->attrs) + GNUNET_IDENTITY_ATTRIBUTE_list_destroy (rh->attrs); + if (NULL != rh->rvk_attrs) + GNUNET_IDENTITY_ATTRIBUTE_list_destroy (rh->rvk_attrs); + if (NULL != rh->abe_key) + GNUNET_ABE_cpabe_delete_master_key (rh->abe_key); + if (NULL != rh->ns_qe) + GNUNET_NAMESTORE_cancel (rh->ns_qe); + if (NULL != rh->ns_it) + GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it); + GNUNET_free (rh); } +/** + * Send revocation result + * + * @param rh ticket revocation handle + * @param success GNUNET_OK if successful result + */ static void -attribute_collect_error_cb (void *cls) +send_revocation_finished (struct TicketRevocationHandle *rh, + uint32_t success) { - struct EgoEntry *ego_entry = cls; + struct GNUNET_MQ_Envelope *env; + struct RevokeTicketResultMessage *trm; - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - ">>> Updating Attributes failed!\n"); - ego_entry->attributes_dirty = GNUNET_NO; - update_task = GNUNET_SCHEDULER_add_now (&update_identities, - ego_entry); + env = GNUNET_MQ_msg (trm, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT); + trm->id = htonl (rh->r_id); + trm->success = htonl (success); + GNUNET_MQ_send (rh->client->mq, + env); + GNUNET_CONTAINER_DLL_remove (rh->client->revocation_list_head, + rh->client->revocation_list_tail, + rh); } +/** + * Process ticket from database + * + * @param cls struct TicketIterationProcResult + * @param ticket the ticket + * @param attrs the attributes + */ +static void +ticket_reissue_proc (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs); + static void -attribute_collect_finished_cb (void *cls) +revocation_reissue_tickets (struct TicketRevocationHandle *rh); + + +static void reissue_next (void *cls) { - struct EgoEntry *ego_entry = cls; + struct TicketRevocationHandle *rh = cls; + revocation_reissue_tickets (rh); +} - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - ">>> Updating Attributes finished\n"); - ego_entry->attributes_dirty = GNUNET_NO; - update_task = GNUNET_SCHEDULER_add_now (&update_identities, - ego_entry); + +static void +reissue_ticket_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct TicketRevocationHandle *rh = cls; + + rh->ns_qe = NULL; + if (GNUNET_SYSERR == success) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", + "Unknown Error\n"); + send_revocation_finished (rh, GNUNET_SYSERR); + cleanup_revoke_ticket_handle (rh); + return; + } + rh->offset++; + GNUNET_SCHEDULER_add_now (&reissue_next, rh); } /** + * Process ticket from database * - * Collect all ID_ATTR records for an identity and store them - * - * @param cls the identity entry - * @param zone the identity - * @param lbl the name of the record - * @param rd_count number of records - * @param rd record data - * + * @param cls struct TicketIterationProcResult + * @param ticket the ticket + * @param attrs the attributes */ static void -attribute_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *lbl, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct EgoEntry *ego_entry = cls; - struct GNUNET_HashCode key; - struct TokenAttr *attr; - struct TokenAttrValue *val; - char *val_str; - int i; - - if (0 == rd_count) +ticket_reissue_proc (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) +{ + struct TicketRevocationHandle *rh = cls; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le_rollover; + struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; + struct GNUNET_GNSRECORD_Data code_record[1]; + struct GNUNET_ABE_AbeKey *rp_key; + char *code_record_data; + char **attr_arr; + char *label; + char *policy; + int attrs_len; + uint32_t i; + int reissue_ticket; + size_t code_record_len; + + + if (NULL == ticket) { - GNUNET_NAMESTORE_zone_iterator_next (ns_it); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Iteration done\n"); return; } - GNUNET_CRYPTO_hash (lbl, - strlen (lbl), - &key); - if (1 == rd_count) + + if (0 == memcmp (&ticket->audience, + &rh->ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) { - if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) - { - val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type, - rd->data, - rd->data_size); - attr = GNUNET_malloc (sizeof (struct TokenAttr)); - attr->name = GNUNET_strdup (lbl); - val = GNUNET_malloc (sizeof (struct TokenAttrValue)); - val->value = val_str; - GNUNET_CONTAINER_DLL_insert (attr->val_head, - attr->val_tail, - val); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map, - &key, - attr, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Do not reissue for this identity.!\n"); - GNUNET_NAMESTORE_zone_iterator_next (ns_it); + rh->offset++; + GNUNET_SCHEDULER_add_now (&reissue_next, rh); return; } - attr = GNUNET_malloc (sizeof (struct TokenAttr)); - attr->name = GNUNET_strdup (lbl); - for (i = 0; i < rd_count; i++) + /* + * Check if any attribute of this ticket intersects with a rollover attribute + */ + reissue_ticket = GNUNET_NO; + for (le = attrs->list_head; NULL != le; le = le->next) { - if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) + for (le_rollover = rh->rvk_attrs->list_head; + NULL != le_rollover; + le_rollover = le_rollover->next) { - val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type, - rd[i].data, - rd[i].data_size); - val = GNUNET_malloc (sizeof (struct TokenAttrValue)); - val->value = val_str; - GNUNET_CONTAINER_DLL_insert (attr->val_head, - attr->val_tail, - val); + if (0 == strcmp (le_rollover->claim->name, + le->claim->name)) + { + reissue_ticket = GNUNET_YES; + le->claim->version = le_rollover->claim->version; + } } } - GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map, - &key, - attr, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - GNUNET_NAMESTORE_zone_iterator_next (ns_it); -} - -/** - * - * Update identity information for ego. If attribute map is - * dirty, first update the attributes. - * - * @param cls the ego to update - */ -static void -update_identities(void *cls) -{ - struct EgoEntry *next_ego = cls; - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - update_task = NULL; - if (NULL == next_ego) + if (GNUNET_NO == reissue_ticket) { - if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us) - min_rel_exp = MIN_WAIT_TIME; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - ">>> Finished. Rescheduling in %"SCNu64"\n", - min_rel_exp.rel_value_us); - ns_it = NULL; - //finished -> reschedule - update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp, - &update_identities, - ego_head); - min_rel_exp.rel_value_us = 0; + "Skipping ticket.\n"); + + rh->offset++; + GNUNET_SCHEDULER_add_now (&reissue_next, rh); + + return; } - priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego); - if (GNUNET_YES == next_ego->attributes_dirty) - { - //Starting over. We must update the Attributes for they might have changed. - ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, - priv_key, - &attribute_collect_error_cb, - next_ego, - &attribute_collect, - next_ego, - &attribute_collect_finished_cb, - next_ego); + //Create new ABE key for RP + attrs_len = 0; + + /* If this is the RP we want to revoke attributes of, the do so */ + + for (le = attrs->list_head; NULL != le; le = le->next) + attrs_len++; + attr_arr = GNUNET_malloc ((attrs_len + 1)*sizeof (char*)); + i = 0; + for (le = attrs->list_head; NULL != le; le = le->next) { + GNUNET_asprintf (&policy, "%s_%lu", + le->claim->name, + le->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Recreating key with %s\n", policy); + attr_arr[i] = policy; + i++; } - else + attr_arr[i] = NULL; + rp_key = GNUNET_ABE_cpabe_create_key (rh->abe_key, + attr_arr); + + //TODO review this wireformat + code_record_len = serialize_abe_keyinfo2 (ticket, + attrs, + rp_key, + &ecdhe_privkey, + &code_record_data); + code_record[0].data = code_record_data; + code_record[0].data_size = code_record_len; + code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us; + code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY; + code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + + label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + //Publish record + rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &rh->identity, + label, + 1, + code_record, + &reissue_ticket_cont, + rh); + //for (; i > 0; i--) + // GNUNET_free (attr_arr[i-1]); + GNUNET_free (ecdhe_privkey); + GNUNET_free (label); + GNUNET_free (attr_arr); + GNUNET_free (code_record_data); + GNUNET_ABE_cpabe_delete_key (rp_key, GNUNET_YES); +} + + +/* Prototype for below function */ +static void +attr_reenc_cont (void *cls, + int32_t success, + const char *emsg); + +static void +revocation_reissue_tickets (struct TicketRevocationHandle *rh) +{ + int ret; + /* Done, issue new keys */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Revocation Phase III: Reissuing Tickets\n"); + if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (TKT_database->cls, + &rh->ticket.identity, + GNUNET_NO, + rh->offset, + &ticket_reissue_proc, + rh))) { - //Ego will be dirty next time - next_ego->attributes_dirty = GNUNET_YES; - ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, - priv_key, - &token_collect_error_cb, - next_ego, - &token_collect, - next_ego, - &token_collect_finished_cb, - next_ego); + GNUNET_break (0); + } + if (GNUNET_NO == ret) + { + send_revocation_finished (rh, GNUNET_OK); + cleanup_revoke_ticket_handle (rh); + return; } } - /** - * Function called initially to start update task + * Revoke next attribte by reencryption with + * new ABE master */ static void -init_cont () +reenc_next_attribute (struct TicketRevocationHandle *rh) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n"); - //Initially iterate all itenties and refresh all tokens - update_task = GNUNET_SCHEDULER_add_now (&update_identities, - ego_head); + struct GNUNET_GNSRECORD_Data rd[1]; + char* buf; + char* enc_buf; + size_t enc_size; + char* rd_buf; + size_t buf_size; + char* policy; + uint32_t attr_ver; + + if (NULL == rh->attrs->list_head) + { + revocation_reissue_tickets (rh); + return; + } + buf_size = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim); + buf = GNUNET_malloc (buf_size); + GNUNET_IDENTITY_ATTRIBUTE_serialize (rh->attrs->list_head->claim, + buf); + rh->attrs->list_head->claim->version++; + GNUNET_asprintf (&policy, "%s_%lu", + rh->attrs->list_head->claim->name, + rh->attrs->list_head->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypting with policy %s\n", policy); + /** + * Encrypt the attribute value and store in namestore + */ + enc_size = GNUNET_ABE_cpabe_encrypt (buf, + buf_size, + policy, //Policy + rh->abe_key, + (void**)&enc_buf); + GNUNET_free (buf); + GNUNET_free (policy); + rd[0].data_size = enc_size + sizeof (uint32_t); + rd_buf = GNUNET_malloc (rd[0].data_size); + attr_ver = htonl (rh->attrs->list_head->claim->version); + GNUNET_memcpy (rd_buf, + &attr_ver, + sizeof (uint32_t)); + GNUNET_memcpy (rd_buf+sizeof (uint32_t), + enc_buf, + enc_size); + rd[0].data = rd_buf; + rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR; + rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane? + rh->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &rh->identity, + rh->attrs->list_head->claim->name, + 1, + rd, + &attr_reenc_cont, + rh); + GNUNET_free (enc_buf); + GNUNET_free (rd_buf); } - /** - * Initial ego collection function. - * - * @param cls NULL - * @param ego ego - * @param ctx context - * @param identifier ego name + * Namestore callback after revoked attribute + * is stored */ static void -list_ego (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *identifier) +attr_reenc_cont (void *cls, + int32_t success, + const char *emsg) { - struct EgoEntry *new_entry; - if ((NULL == ego) && (STATE_INIT == state)) + struct TicketRevocationHandle *rh = cls; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + + if (GNUNET_SYSERR == success) { - state = STATE_POST_INIT; - init_cont (); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to reencrypt attribute %s\n", + emsg); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); return; } - if (STATE_INIT == state) { - new_entry = GNUNET_malloc (sizeof (struct EgoEntry)); - new_entry->ego = ego; - new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5, - GNUNET_NO); - new_entry->attributes_dirty = GNUNET_YES; - GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry); + if (NULL == rh->attrs->list_head) + { + revocation_reissue_tickets (rh); + return; } + le = rh->attrs->list_head; + GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head, + rh->attrs->list_tail, + le); + GNUNET_assert (NULL != rh->rvk_attrs); + GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head, + rh->rvk_attrs->list_tail, + le); + + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Re-encrypting next attribute\n"); + reenc_next_attribute (rh); } -/** - * Cleanup task - */ + static void -cleanup() +process_attributes_to_update (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) { - struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; + struct TicketRevocationHandle *rh = cls; + rh->attrs = GNUNET_IDENTITY_ATTRIBUTE_list_dup (attrs); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Cleaning up\n"); - if (NULL != stats) + "Revocation Phase I: Collecting attributes\n"); + /* Reencrypt all attributes with new key */ + if (NULL == rh->attrs->list_head) { - GNUNET_STATISTICS_destroy (stats, GNUNET_NO); - stats = NULL; + /* No attributes to reencrypt */ + send_revocation_finished (rh, GNUNET_OK); + cleanup_revoke_ticket_handle (rh); + return; + } else { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Revocation Phase II: Re-encrypting attributes\n"); + reenc_next_attribute (rh); } - if (NULL != timeout_task) - GNUNET_SCHEDULER_cancel (timeout_task); - if (NULL != update_task) - GNUNET_SCHEDULER_cancel (update_task); - if (NULL != identity_handle) - GNUNET_IDENTITY_disconnect (identity_handle); - if (NULL != gns_handle) - GNUNET_GNS_disconnect (gns_handle); - if (NULL != ns_it) - GNUNET_NAMESTORE_zone_iteration_stop (ns_it); - if (NULL != ns_qe) - GNUNET_NAMESTORE_cancel (ns_qe); - if (NULL != ns_handle) - GNUNET_NAMESTORE_disconnect (ns_handle); - if (NULL != token) - GNUNET_free (token); - if (NULL != label) - GNUNET_free (label); +} - for (ego_entry = ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map)) - { - GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map, - &clear_ego_attrs, - ego_tmp); - } - GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map); - ego_entry = ego_entry->next; - GNUNET_free (ego_tmp); + +static void +get_ticket_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished ABE bootstrap\n"); + struct TicketRevocationHandle *rh = cls; + rh->abe_key = abe_key; + TKT_database->get_ticket_attributes (TKT_database->cls, + &rh->ticket, + &process_attributes_to_update, + rh); +} + +static int +check_revoke_ticket_message(void *cls, + const struct RevokeTicketMessage *im) +{ + uint16_t size; + + size = ntohs (im->header.size); + if (size <= sizeof (struct RevokeTicketMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; } + return GNUNET_OK; } -/** - * Shutdown task - * - * @param cls NULL - * @param tc task context - */ static void -do_shutdown (void *cls) +handle_revoke_ticket_message (void *cls, + const struct RevokeTicketMessage *rm) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Shutting down...\n"); - cleanup(); + struct TicketRevocationHandle *rh; + struct IdpClient *idp = cls; + struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; + + rh = GNUNET_new (struct TicketRevocationHandle); + ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket*)&rm[1]; + rh->rvk_attrs = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); + rh->ticket = *ticket; + rh->r_id = ntohl (rm->id); + rh->client = idp; + rh->identity = rm->identity; + GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity, + &rh->ticket.identity); + GNUNET_CONTAINER_DLL_insert (idp->revocation_list_head, + idp->revocation_list_tail, + rh); + bootstrap_abe (&rh->identity, &get_ticket_after_abe_bootstrap, rh, GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); + } -static struct GNUNET_MQ_Envelope* -create_exchange_result_message (const char* token, - const char* label, - uint64_t ticket_nonce, - uint64_t id) +static void +cleanup_consume_ticket_handle (struct ConsumeTicketHandle *handle) { - struct GNUNET_MQ_Envelope *env; - struct ExchangeResultMessage *erm; - uint16_t token_len = strlen (token) + 1; - - env = GNUNET_MQ_msg_extra (erm, - token_len, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT); - erm->ticket_nonce = htonl (ticket_nonce); - erm->id = id; - GNUNET_memcpy (&erm[1], token, token_len); - return env; + if (NULL != handle->key) + GNUNET_ABE_cpabe_delete_key (handle->key, + GNUNET_YES); + if (NULL != handle->attrs) + GNUNET_IDENTITY_ATTRIBUTE_list_destroy (handle->attrs); + GNUNET_free (handle); } -static struct GNUNET_MQ_Envelope* -create_issue_result_message (const char* label, - const char* ticket, - const char* token, - uint64_t id) + +static int +check_consume_ticket_message(void *cls, + const struct ConsumeTicketMessage *cm) { - struct GNUNET_MQ_Envelope *env; - struct IssueResultMessage *irm; - char *tmp_str; - size_t len; + uint16_t size; - GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token); - len = strlen (tmp_str) + 1; - env = GNUNET_MQ_msg_extra (irm, - len, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT); - irm->id = id; - GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1); - GNUNET_free (tmp_str); - return env; + size = ntohs (cm->header.size); + if (size <= sizeof (struct ConsumeTicketMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; } static void -cleanup_issue_handle (struct IssueHandle *handle) -{ - if (NULL != handle->attr_map) - GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map); - if (NULL != handle->scopes) - GNUNET_free (handle->scopes); - if (NULL != handle->token) - token_destroy (handle->token); - if (NULL != handle->ticket) - ticket_destroy (handle->ticket); - if (NULL != handle->label) - GNUNET_free (handle->label); - GNUNET_free (handle); +process_parallel_lookup2 (void *cls, uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Parallel lookup finished (count=%u)\n", rd_count); + struct ParallelLookup *parallel_lookup = cls; + struct ConsumeTicketHandle *handle = parallel_lookup->handle; + struct ConsumeTicketResultMessage *crm; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *attr_le; + struct GNUNET_TIME_Absolute decrypt_duration; + char *data; + char *data_tmp; + ssize_t attr_len; + size_t attrs_len; + + GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + parallel_lookup); + GNUNET_free (parallel_lookup->label); + + GNUNET_STATISTICS_update (stats_handle, + "attribute_lookup_time_total", + GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time).rel_value_us, + GNUNET_YES); + GNUNET_STATISTICS_update (stats_handle, + "attribute_lookups_count", + 1, + GNUNET_YES); + + + GNUNET_free (parallel_lookup); + if (1 != rd_count) + GNUNET_break(0);//TODO + if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) + { + decrypt_duration = GNUNET_TIME_absolute_get (); + attr_len = GNUNET_ABE_cpabe_decrypt (rd->data + sizeof (uint32_t), + rd->data_size - sizeof (uint32_t), + handle->key, + (void**)&data); + if (GNUNET_SYSERR != attr_len) + { + GNUNET_STATISTICS_update (stats_handle, + "abe_decrypt_time_total", + GNUNET_TIME_absolute_get_duration (decrypt_duration).rel_value_us, + GNUNET_YES); + GNUNET_STATISTICS_update (stats_handle, + "abe_decrypt_count", + 1, + GNUNET_YES); + + attr_le = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry); + attr_le->claim = GNUNET_IDENTITY_ATTRIBUTE_deserialize (data, + attr_len); + attr_le->claim->version = ntohl(*(uint32_t*)rd->data); + GNUNET_CONTAINER_DLL_insert (handle->attrs->list_head, + handle->attrs->list_tail, + attr_le); + GNUNET_free (data); + } + } + if (NULL != handle->parallel_lookups_head) + return; //Wait for more + /* Else we are done */ + + /* Store ticket in DB */ + if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls, + &handle->ticket, + handle->attrs)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to store ticket after consume\n"); + GNUNET_break (0); + } + + GNUNET_SCHEDULER_cancel (handle->kill_task); + attrs_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (handle->attrs); + env = GNUNET_MQ_msg_extra (crm, + attrs_len, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT); + crm->id = htonl (handle->r_id); + crm->attrs_len = htons (attrs_len); + crm->identity = handle->ticket.identity; + data_tmp = (char *) &crm[1]; + GNUNET_IDENTITY_ATTRIBUTE_list_serialize (handle->attrs, + data_tmp); + GNUNET_MQ_send (handle->client->mq, env); + cleanup_consume_ticket_handle (handle); } -static void -store_token_issue_cont (void *cls, - int32_t success, - const char *emsg) +void +abort_parallel_lookups2 (void *cls) { - struct IssueHandle *handle = cls; + struct ConsumeTicketHandle *handle = cls; + struct ParallelLookup *lu; + struct ParallelLookup *tmp; + struct AttributeResultMessage *arm; struct GNUNET_MQ_Envelope *env; - char *ticket_str; - char *token_str; - handle->ns_qe = NULL; - if (GNUNET_SYSERR == success) + for (lu = handle->parallel_lookups_head; + NULL != lu;) { + GNUNET_GNS_lookup_cancel (lu->lookup_request); + GNUNET_free (lu->label); + tmp = lu->next; + GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + lu); + GNUNET_free (lu); + lu = tmp; + } + env = GNUNET_MQ_msg (arm, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT); + arm->id = htonl (handle->r_id); + arm->attr_len = htons (0); + GNUNET_MQ_send (handle->client->mq, env); + +} + + +static void +process_consume_abe_key (void *cls, uint32_t rd_count, + const struct GNUNET_GNSRECORD_Data *rd) +{ + struct ConsumeTicketHandle *handle = cls; + struct GNUNET_HashCode new_key_hash; + struct GNUNET_CRYPTO_SymmetricSessionKey enc_key; + struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv; + struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key; + struct ParallelLookup *parallel_lookup; + size_t size; + char *buf; + char *scope; + char *lookup_query; + + handle->lookup_request = NULL; + if (1 != rd_count) { - cleanup_issue_handle (handle); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", - "Unknown Error\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Number of keys %d != 1.", + rd_count); + cleanup_consume_ticket_handle (handle); GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); return; } - if (GNUNET_OK != ticket_serialize (handle->ticket, - &handle->iss_key, - &ticket_str)) + + //Decrypt + ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data; + + buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + + //Calculate symmetric key from ecdh parameters + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_ecdsa_ecdh (&handle->identity, + ecdh_key, + &new_key_hash)); + create_sym_key_from_ecdh (&new_key_hash, + &enc_key, + &enc_iv); + size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), + rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey), + &enc_key, + &enc_iv, + buf); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Decrypted bytes: %zd Expected bytes: %zd\n", + size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + GNUNET_STATISTICS_update (stats_handle, + "abe_key_lookup_time_total", + GNUNET_TIME_absolute_get_duration (handle->lookup_start_time).rel_value_us, + GNUNET_YES); + GNUNET_STATISTICS_update (stats_handle, + "abe_key_lookups_count", + 1, + GNUNET_YES); + scopes = GNUNET_strdup (buf); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Scopes %s\n", scopes); + handle->key = GNUNET_ABE_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1), + rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + - strlen (scopes) - 1); + + for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ",")) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", - "Error serializing ticket\n"); - cleanup_issue_handle (handle); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); - return; + GNUNET_asprintf (&lookup_query, + "%s.gnu", + scope); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking up %s\n", lookup_query); + parallel_lookup = GNUNET_new (struct ParallelLookup); + parallel_lookup->handle = handle; + parallel_lookup->label = GNUNET_strdup (scope); + parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get(); + parallel_lookup->lookup_request + = GNUNET_GNS_lookup (gns_handle, + lookup_query, + &handle->ticket.identity, + GNUNET_GNSRECORD_TYPE_ID_ATTR, + GNUNET_GNS_LO_DEFAULT, + &process_parallel_lookup2, + parallel_lookup); + GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head, + handle->parallel_lookups_tail, + parallel_lookup); + GNUNET_free (lookup_query); } - if (GNUNET_OK != token_to_string (handle->token, - &handle->iss_key, - &token_str)) + GNUNET_free (scopes); + GNUNET_free (buf); + handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3), + &abort_parallel_lookups2, + handle); +} + + +static void +handle_consume_ticket_message (void *cls, + const struct ConsumeTicketMessage *cm) +{ + struct ConsumeTicketHandle *ch; + struct IdpClient *idp = cls; + char* lookup_query; + char* rnd_label; + + ch = GNUNET_new (struct ConsumeTicketHandle); + ch->r_id = ntohl (cm->id); + ch->client = idp; + ch->identity = cm->identity; + ch->attrs = GNUNET_new (struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList); + GNUNET_CRYPTO_ecdsa_key_get_public (&ch->identity, + &ch->identity_pub); + ch->ticket = *((struct GNUNET_IDENTITY_PROVIDER_Ticket*)&cm[1]); + rnd_label = GNUNET_STRINGS_data_to_string_alloc (&ch->ticket.rnd, + sizeof (uint64_t)); + GNUNET_asprintf (&lookup_query, + "%s.gnu", + rnd_label); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Looking for ABE key under %s\n", lookup_query); + ch->lookup_start_time = GNUNET_TIME_absolute_get (); + ch->lookup_request + = GNUNET_GNS_lookup (gns_handle, + lookup_query, + &ch->ticket.identity, + GNUNET_GNSRECORD_TYPE_ABE_KEY, + GNUNET_GNS_LO_DEFAULT, + &process_consume_abe_key, + ch); + GNUNET_free (rnd_label); + GNUNET_free (lookup_query); + GNUNET_SERVICE_client_continue (idp->client); +} + +static void +cleanup_as_handle (struct AttributeStoreHandle *handle) +{ + if (NULL != handle->claim) + GNUNET_free (handle->claim); + if (NULL != handle->abe_key) + GNUNET_ABE_cpabe_delete_master_key (handle->abe_key); + GNUNET_free (handle); +} + +static void +attr_store_cont (void *cls, + int32_t success, + const char *emsg) +{ + struct AttributeStoreHandle *as_handle = cls; + struct GNUNET_MQ_Envelope *env; + struct AttributeStoreResultMessage *acr_msg; + + if (GNUNET_SYSERR == success) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", - "Error serializing token\n"); - GNUNET_free (ticket_str); - cleanup_issue_handle (handle); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to store attribute %s\n", + emsg); + cleanup_as_handle (as_handle); GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); return; } - env = create_issue_result_message (handle->label, - ticket_str, - token_str, - handle->r_id); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client), + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending ATTRIBUTE_STORE_RESPONSE message\n"); + env = GNUNET_MQ_msg (acr_msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE); + acr_msg->id = htonl (as_handle->r_id); + acr_msg->op_result = htonl (GNUNET_OK); + GNUNET_MQ_send (as_handle->client->mq, env); - cleanup_issue_handle (handle); - GNUNET_free (ticket_str); - GNUNET_free (token_str); + cleanup_as_handle (as_handle); } - -/** - * Build a token and store it - * - * @param cls the IssueHandle - */ static void -sign_and_return_token (void *cls) +attr_store_task (void *cls) { - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; - struct IssueHandle *handle = cls; - struct GNUNET_GNSRECORD_Data token_record[2]; - char *nonce_str; - char *enc_token_str; - char *token_metadata; - char* write_ptr; - uint64_t time; - uint64_t exp_time; - size_t token_metadata_len; - - //Remote nonce - nonce_str = NULL; - GNUNET_asprintf (&nonce_str, "%lu", handle->nonce); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str); - - GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key, - &pub_key); - handle->ticket = ticket_create (handle->nonce, - &pub_key, - handle->label, - &handle->aud_key); - - time = GNUNET_TIME_absolute_get().abs_value_us; - exp_time = time + token_expiration_interval.rel_value_us; - - token_add_attr_int (handle->token, "nbf", time); - token_add_attr_int (handle->token, "iat", time); - token_add_attr_int (handle->token, "exp", exp_time); - token_add_attr (handle->token, "nonce", nonce_str); - - //Token in a serialized encrypted format - GNUNET_assert (token_serialize (handle->token, - &handle->iss_key, - &ecdhe_privkey, - &enc_token_str)); - - //Token record E,E_K (Token) - token_record[0].data = enc_token_str; - token_record[0].data_size = strlen (enc_token_str) + 1; - token_record[0].expiration_time = exp_time; - token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN; - token_record[0].flags = GNUNET_GNSRECORD_RF_NONE; - - - token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey) - + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey) - + strlen (handle->scopes) + 1; //With 0-Terminator - token_metadata = GNUNET_malloc (token_metadata_len); - write_ptr = token_metadata; - GNUNET_memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); - write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey); - GNUNET_memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey); - GNUNET_memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator; - - token_record[1].data = token_metadata; - token_record[1].data_size = token_metadata_len; - token_record[1].expiration_time = exp_time; - token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA; - token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE; - - //Persist token - handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, - &handle->iss_key, - handle->label, - 2, - token_record, - &store_token_issue_cont, - handle); - GNUNET_free (ecdhe_privkey); - GNUNET_free (nonce_str); - GNUNET_free (enc_token_str); - GNUNET_free (token_metadata); + struct AttributeStoreHandle *as_handle = cls; + struct GNUNET_GNSRECORD_Data rd[1]; + char* buf; + char* policy; + char* enc_buf; + char* rd_buf; + size_t enc_size; + size_t buf_size; + uint32_t attr_ver; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Storing attribute\n"); + buf_size = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (as_handle->claim); + buf = GNUNET_malloc (buf_size); + + GNUNET_IDENTITY_ATTRIBUTE_serialize (as_handle->claim, + buf); + + GNUNET_asprintf (&policy, + "%s_%lu", + as_handle->claim->name, + as_handle->claim->version); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Encrypting with policy %s\n", policy); + /** + * Encrypt the attribute value and store in namestore + */ + enc_size = GNUNET_ABE_cpabe_encrypt (buf, + buf_size, + policy, //Policy + as_handle->abe_key, + (void**)&enc_buf); + GNUNET_free (buf); + GNUNET_free (policy); + rd[0].data_size = enc_size + sizeof (uint32_t); + rd_buf = GNUNET_malloc (rd[0].data_size); + attr_ver = htonl (as_handle->claim->version); + GNUNET_memcpy (rd_buf, + &attr_ver, + sizeof (uint32_t)); + GNUNET_memcpy (rd_buf+sizeof (uint32_t), + enc_buf, + enc_size); + rd[0].data = rd_buf; + rd[0].record_type = GNUNET_GNSRECORD_TYPE_ID_ATTR; + rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; + rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane? + as_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle, + &as_handle->identity, + as_handle->claim->name, + 1, + rd, + &attr_store_cont, + as_handle); + GNUNET_free (enc_buf); + GNUNET_free (rd_buf); } static void -attr_collect_error (void *cls) +store_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) { - struct IssueHandle *handle = cls; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Finished ABE bootstrap\n"); + struct AttributeStoreHandle *ash = cls; + ash->abe_key = abe_key; + GNUNET_SCHEDULER_add_now (&attr_store_task, ash); +} - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n"); - handle->ns_it = NULL; - GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle); +static int +check_attribute_store_message(void *cls, + const struct AttributeStoreMessage *sam) +{ + uint16_t size; + + size = ntohs (sam->header.size); + if (size <= sizeof (struct AttributeStoreMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; } static void -attr_collect_finished (void *cls) +handle_attribute_store_message (void *cls, + const struct AttributeStoreMessage *sam) { - struct IssueHandle *handle = cls; + struct AttributeStoreHandle *as_handle; + struct IdpClient *idp = cls; + size_t data_len; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_STORE message\n"); + + data_len = ntohs (sam->attr_len); + + as_handle = GNUNET_new (struct AttributeStoreHandle); + as_handle->claim = GNUNET_IDENTITY_ATTRIBUTE_deserialize ((char*)&sam[1], + data_len); + + as_handle->r_id = ntohl (sam->id); + as_handle->identity = sam->identity; + GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, + &as_handle->identity_pkey); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n"); - handle->ns_it = NULL; - GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle); + GNUNET_SERVICE_client_continue (idp->client); + as_handle->client = idp; + bootstrap_abe (&as_handle->identity, &store_after_abe_bootstrap, as_handle, GNUNET_NO); } +static void +cleanup_iter_handle (struct AttributeIterator *ai) +{ + if (NULL != ai->abe_key) + GNUNET_ABE_cpabe_delete_master_key (ai->abe_key); + GNUNET_CONTAINER_DLL_remove (ai->client->op_head, + ai->client->op_tail, + ai); + GNUNET_free (ai); +} + +static void +attr_iter_error (void *cls) +{ + struct AttributeIterator *ai = cls; + //TODO + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to iterate over attributes\n"); + cleanup_iter_handle (ai); + GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); +} + +static void +attr_iter_finished (void *cls) +{ + struct AttributeIterator *ai = cls; + struct GNUNET_MQ_Envelope *env; + struct AttributeResultMessage *arm; + + env = GNUNET_MQ_msg (arm, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT); + arm->id = htonl (ai->request_id); + arm->attr_len = htons (0); + GNUNET_MQ_send (ai->client->mq, env); + cleanup_iter_handle (ai); +} -/** - * Collect attributes for token - */ static void -attr_collect (void *cls, +attr_iter_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, const char *label, unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd) { - struct IssueHandle *handle = cls; - int i; - char* data; - struct GNUNET_HashCode key; - - GNUNET_CRYPTO_hash (label, - strlen (label), - &key); - - if (0 == rd_count || - ( (NULL != handle->attr_map) && - (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, - &key)) - ) - ) + struct AttributeIterator *ai = cls; + struct AttributeResultMessage *arm; + struct GNUNET_ABE_AbeKey *key; + struct GNUNET_MQ_Envelope *env; + ssize_t msg_extra_len; + char* attr_ser; + char* attrs[2]; + char* data_tmp; + char* policy; + uint32_t attr_ver; + + if (rd_count != 1) { - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label); - - if (1 == rd_count) - { - if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) - { - data = GNUNET_GNSRECORD_value_to_string (rd->record_type, - rd->data, - rd->data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data); - token_add_attr (handle->token, - label, - data); - GNUNET_free (data); - } - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); + if (GNUNET_GNSRECORD_TYPE_ID_ATTR != rd->record_type) { + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it); return; } + attr_ver = ntohl(*((uint32_t*)rd->data)); + GNUNET_asprintf (&policy, "%s_%lu", + label, attr_ver); + attrs[0] = policy; + attrs[1] = 0; + key = GNUNET_ABE_cpabe_create_key (ai->abe_key, + attrs); + msg_extra_len = GNUNET_ABE_cpabe_decrypt (rd->data+sizeof (uint32_t), + rd->data_size-sizeof (uint32_t), + key, + (void**)&attr_ser); + + GNUNET_ABE_cpabe_delete_key (key, + GNUNET_YES); + //GNUNET_free (policy); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Found attribute: %s\n", label); + env = GNUNET_MQ_msg_extra (arm, + msg_extra_len, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT); + arm->id = htonl (ai->request_id); + arm->attr_len = htons (msg_extra_len); + GNUNET_CRYPTO_ecdsa_key_get_public (zone, + &arm->identity); + data_tmp = (char *) &arm[1]; + GNUNET_memcpy (data_tmp, + attr_ser, + msg_extra_len); + GNUNET_MQ_send (ai->client->mq, env); + GNUNET_free (attr_ser); + GNUNET_ABE_cpabe_delete_master_key (ai->abe_key); + ai->abe_key = NULL; +} - i = 0; - for (; i < rd_count; i++) - { - if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR) - { - data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type, - rd[i].data, - rd[i].data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data); - token_add_attr (handle->token, label, data); - GNUNET_free (data); - } - } - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); +void +iterate_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + struct AttributeIterator *ai = cls; + ai->abe_key = abe_key; + ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, + &ai->identity, + &attr_iter_error, + ai, + &attr_iter_cb, + ai, + &attr_iter_finished, + ai); } +void +iterate_next_after_abe_bootstrap (void *cls, + struct GNUNET_ABE_AbeMasterKey *abe_key) +{ + struct AttributeIterator *ai = cls; + ai->abe_key = abe_key; + GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it); +} + + + static void -cleanup_exchange_handle (struct ExchangeHandle *handle) +handle_iteration_start (void *cls, + const struct AttributeIterationStartMessage *ais_msg) { - if (NULL != handle->ticket) - ticket_destroy (handle->ticket); - if (NULL != handle->token) - token_destroy (handle->token); - GNUNET_free (handle); + struct IdpClient *idp = cls; + struct AttributeIterator *ai; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_ITERATION_START message\n"); + ai = GNUNET_new (struct AttributeIterator); + ai->request_id = ntohl (ais_msg->id); + ai->client = idp; + ai->identity = ais_msg->identity; + + GNUNET_CONTAINER_DLL_insert (idp->op_head, + idp->op_tail, + ai); + bootstrap_abe (&ai->identity, &iterate_after_abe_bootstrap, ai, GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); } + static void -process_lookup_result (void *cls, uint32_t rd_count, - const struct GNUNET_GNSRECORD_Data *rd) +handle_iteration_stop (void *cls, + const struct AttributeIterationStopMessage *ais_msg) { - struct ExchangeHandle *handle = cls; - struct GNUNET_MQ_Envelope *env; - char* token_str; - char* record_str; + struct IdpClient *idp = cls; + struct AttributeIterator *ai; + uint32_t rid; - handle->lookup_request = NULL; - if (2 != rd_count) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' message\n", + "ATTRIBUTE_ITERATION_STOP"); + rid = ntohl (ais_msg->id); + for (ai = idp->op_head; NULL != ai; ai = ai->next) + if (ai->request_id == rid) + break; + if (NULL == ai) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Number of tokens %d != 2.", - rd_count); - cleanup_exchange_handle (handle); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); + GNUNET_break (0); + GNUNET_SERVICE_client_drop (idp->client); return; } - - record_str = - GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN, - rd->data, - rd->data_size); - - //Decrypt and parse - GNUNET_assert (GNUNET_OK == token_parse (record_str, - &handle->aud_privkey, - &handle->token)); - - //Readable - GNUNET_assert (GNUNET_OK == token_to_string (handle->token, - &handle->aud_privkey, - &token_str)); - - env = create_exchange_result_message (token_str, - handle->label, - handle->ticket->payload->nonce, - handle->r_id); - GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client), - env); - cleanup_exchange_handle (handle); - GNUNET_free (record_str); - GNUNET_free (token_str); + GNUNET_CONTAINER_DLL_remove (idp->op_head, + idp->op_tail, + ai); + GNUNET_free (ai); + GNUNET_SERVICE_client_continue (idp->client); } -/** - * Checks a exchange message - * - * @param cls client sending the message - * @param xm message of type `struct ExchangeMessage` - * @return #GNUNET_OK if @a xm is well-formed - */ -static int -check_exchange_message (void *cls, - const struct ExchangeMessage *xm) + +static void +handle_iteration_next (void *cls, + const struct AttributeIterationNextMessage *ais_msg) { - uint16_t size; + struct IdpClient *idp = cls; + struct AttributeIterator *ai; + uint32_t rid; - size = ntohs (xm->header.size); - if (size <= sizeof (struct ExchangeMessage)) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_ITERATION_NEXT message\n"); + rid = ntohl (ais_msg->id); + for (ai = idp->op_head; NULL != ai; ai = ai->next) + if (ai->request_id == rid) + break; + if (NULL == ai) { GNUNET_break (0); - return GNUNET_SYSERR; + GNUNET_SERVICE_client_drop (idp->client); + return; } - return GNUNET_OK; + bootstrap_abe (&ai->identity, + &iterate_next_after_abe_bootstrap, + ai, + GNUNET_NO); + GNUNET_SERVICE_client_continue (idp->client); } /** - * - * Handler for exchange message - * - * @param cls unused - * @param client who sent the message - * @param message the message + * Ticket iteration processor result */ -static void -handle_exchange_message (void *cls, - const struct ExchangeMessage *xm) +enum ZoneIterationResult { - struct ExchangeHandle *xchange_handle; - struct GNUNET_SERVICE_Client *client = cls; - const char *ticket; - char *lookup_query; + /** + * Iteration start. + */ + IT_START = 0, - ticket = (const char *) &xm[1]; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received EXCHANGE of `%s' from client\n", - ticket); - xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle)); - xchange_handle->aud_privkey = xm->aud_privkey; - xchange_handle->r_id = xm->id; - if (GNUNET_SYSERR == ticket_parse (ticket, - &xchange_handle->aud_privkey, - &xchange_handle->ticket)) - { - GNUNET_free (xchange_handle); - GNUNET_SERVICE_client_drop (client); - return; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n", - xchange_handle->ticket->payload->label); - GNUNET_asprintf (&lookup_query, - "%s.gnu", - xchange_handle->ticket->payload->label); - GNUNET_SERVICE_client_continue (client); - xchange_handle->client = client; - xchange_handle->lookup_request - = GNUNET_GNS_lookup (gns_handle, - lookup_query, - &xchange_handle->ticket->payload->identity_key, - GNUNET_GNSRECORD_TYPE_ID_TOKEN, - GNUNET_GNS_LO_LOCAL_MASTER, - &process_lookup_result, - xchange_handle); - GNUNET_free (lookup_query); + /** + * Found tickets, + * Continue to iterate with next iteration_next call + */ + IT_SUCCESS_MORE_AVAILABLE = 1, -} + /** + * Iteration complete + */ + IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2 +}; -static void -find_existing_token_error (void *cls) +/** + * Context for ticket iteration + */ +struct TicketIterationProcResult { - struct IssueHandle *handle = cls; - cleanup_issue_handle (handle); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error looking for existing token\n"); - GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); -} + /** + * The ticket iteration handle + */ + struct TicketIteration *ti; + /** + * Iteration result: iteration done? + * #IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but + * we got one for now and have sent it to the client + * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results, + * #IT_START: if we are still trying to find a result. + */ + int res_iteration_finished; + +}; static void -find_existing_token_finished (void *cls) +cleanup_ticket_iter_handle (struct TicketIteration *ti) { - struct IssueHandle *handle = cls; - uint64_t rnd_key; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - ">>> No existing token found\n"); - rnd_key = - GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, - UINT64_MAX); - GNUNET_STRINGS_base64_encode ((char*)&rnd_key, - sizeof (uint64_t), - &handle->label); - handle->ns_it = NULL; - handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, - &handle->iss_key, - &attr_collect_error, - handle, - &attr_collect, - handle, - &attr_collect_finished, - handle); + GNUNET_free (ti); } - /** + * Process ticket from database * - * Look for existing token - * - * @param cls the identity entry - * @param zone the identity - * @param lbl the name of the record - * @param rd_count number of records - * @param rd record data - * + * @param cls struct TicketIterationProcResult + * @param ticket the ticket + * @param attrs the attributes */ static void -find_existing_token (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *lbl, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct IssueHandle *handle = cls; - const struct GNUNET_GNSRECORD_Data *token_metadata_record; - struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key; - struct GNUNET_HashCode key; - int scope_count_token; - char *scope; - char *tmp_scopes; +ticket_iterate_proc (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) +{ + struct TicketIterationProcResult *proc = cls; - //There should be only a single record for a token under a label - if (2 != rd_count) + if (NULL == ticket) { - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Iteration done\n"); + proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE; return; } + proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE; + send_ticket_result (proc->ti->client, + proc->ti->r_id, + ticket, + attrs); - if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA) - { - token_metadata_record = &rd[0]; - } - else - { - token_metadata_record = &rd[1]; - } - if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA) - { - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); - return; - } - ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data); - aud_key = - (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey)); - tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); +} - if (0 != memcmp (aud_key, &handle->aud_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) - { - char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - //Audience does not match! - char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA, - token_metadata_record->data, - token_metadata_record->data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Token does not match audience %s vs %s. Moving on\n", - tmp2, - tmp); - GNUNET_free (tmp_scopes); - GNUNET_free (tmp2); - GNUNET_free (tmp); - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); - return; - } +/** + * Perform ticket iteration step + * + * @param ti ticket iterator to process + */ +static void +run_ticket_iteration_round (struct TicketIteration *ti) +{ + struct TicketIterationProcResult proc; + struct GNUNET_MQ_Envelope *env; + struct TicketResultMessage *trm; + int ret; - scope = strtok (tmp_scopes, ","); - scope_count_token = 0; - while (NULL != scope) + memset (&proc, 0, sizeof (proc)); + proc.ti = ti; + proc.res_iteration_finished = IT_START; + while (IT_START == proc.res_iteration_finished) { - GNUNET_CRYPTO_hash (scope, - strlen (scope), - &key); - - if ((NULL != handle->attr_map) && - (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key))) + if (GNUNET_SYSERR == + (ret = TKT_database->iterate_tickets (TKT_database->cls, + &ti->identity, + ti->is_audience, + ti->offset, + &ticket_iterate_proc, + &proc))) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Issued token does not include `%s'. Moving on\n", scope); - GNUNET_free (tmp_scopes); - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); - return; + GNUNET_break (0); + break; } - scope_count_token++; - scope = strtok (NULL, ","); + if (GNUNET_NO == ret) + proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE; + ti->offset++; } - GNUNET_free (tmp_scopes); - //All scopes in token are also in request. Now - //Check length - if ((NULL != handle->attr_map) && - (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token)) + if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished) { - //We have an existing token - handle->label = GNUNET_strdup (lbl); - handle->ns_it = NULL; - handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, - &handle->iss_key, - &attr_collect_error, - handle, - &attr_collect, - handle, - &attr_collect_finished, - handle); - - return; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "More results available\n"); + return; /* more later */ } - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Nuber of attributes in token do not match request\n"); - //No luck - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); + /* send empty response to indicate end of list */ + env = GNUNET_MQ_msg (trm, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT); + trm->id = htonl (ti->r_id); + GNUNET_MQ_send (ti->client->mq, + env); + GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head, + ti->client->ticket_iter_tail, + ti); + cleanup_ticket_iter_handle (ti); } -/** - * Checks an issue message - * - * @param cls client sending the message - * @param im message of type `struct IssueMessage` - * @return #GNUNET_OK if @a im is well-formed - */ -static int -check_issue_message(void *cls, - const struct IssueMessage *im) +static void +handle_ticket_iteration_start (void *cls, + const struct TicketIterationStartMessage *tis_msg) { - uint16_t size; + struct IdpClient *client = cls; + struct TicketIteration *ti; - size = ntohs (im->header.size); - if (size <= sizeof (struct IssueMessage)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - scopes = (char *) &im[1]; - if ('\0' != scopes[size - sizeof (struct IssueMessage) - 1]) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TICKET_ITERATION_START message\n"); + ti = GNUNET_new (struct TicketIteration); + ti->r_id = ntohl (tis_msg->id); + ti->offset = 0; + ti->client = client; + ti->identity = tis_msg->identity; + ti->is_audience = ntohl (tis_msg->is_audience); + + GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head, + client->ticket_iter_tail, + ti); + run_ticket_iteration_round (ti); + GNUNET_SERVICE_client_continue (client->client); +} + + +static void +handle_ticket_iteration_stop (void *cls, + const struct TicketIterationStopMessage *tis_msg) +{ + struct IdpClient *client = cls; + struct TicketIteration *ti; + uint32_t rid; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received `%s' message\n", + "TICKET_ITERATION_STOP"); + rid = ntohl (tis_msg->id); + for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next) + if (ti->r_id == rid) + break; + if (NULL == ti) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Malformed scopes received!\n"); GNUNET_break (0); - return GNUNET_SYSERR; + GNUNET_SERVICE_client_drop (client->client); + return; } - return GNUNET_OK; + GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head, + client->ticket_iter_tail, + ti); + cleanup_ticket_iter_handle (ti); + GNUNET_SERVICE_client_continue (client->client); } -/** - * - * Handler for issue message - * - * @param cls unused - * @param client who sent the message - * @param message the message - */ + static void -handle_issue_message (void *cls, - const struct IssueMessage *im) +handle_ticket_iteration_next (void *cls, + const struct TicketIterationNextMessage *tis_msg) { - const char *scopes; - char *scopes_tmp; - char *scope; - struct GNUNET_HashCode key; - struct IssueHandle *issue_handle; - struct GNUNET_SERVICE_Client *client = cls; - - scopes = (const char *) &im[1]; - issue_handle = GNUNET_malloc (sizeof (struct IssueHandle)); - issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5, - GNUNET_NO); - scopes_tmp = GNUNET_strdup (scopes); + struct IdpClient *client = cls; + struct TicketIteration *ti; + uint32_t rid; - for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ",")) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TICKET_ITERATION_NEXT message\n"); + rid = ntohl (tis_msg->id); + for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next) + if (ti->r_id == rid) + break; + if (NULL == ti) { - GNUNET_CRYPTO_hash (scope, - strlen (scope), - &key); - GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map, - &key, - scope, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + GNUNET_break (0); + GNUNET_SERVICE_client_drop (client->client); + return; } - GNUNET_free (scopes_tmp); - issue_handle->r_id = im->id; - issue_handle->aud_key = im->aud_key; - issue_handle->iss_key = im->iss_key; - GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key, - &issue_handle->iss_pkey); - issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration); - issue_handle->nonce = ntohl (im->nonce); - GNUNET_SERVICE_client_continue (client); - issue_handle->client = client; - issue_handle->scopes = GNUNET_strdup (scopes); - issue_handle->token = token_create (&issue_handle->iss_pkey, - &issue_handle->aud_key); - - issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle, - &im->iss_key, - &find_existing_token_error, - issue_handle, - &find_existing_token, - issue_handle, - &find_existing_token_finished, - issue_handle); + run_ticket_iteration_round (ti); + GNUNET_SERVICE_client_continue (client->client); } + + /** * Main function that will be run * * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL) - * @param c configuration + * @param c the configuration used + * @param server the service handle */ static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *server) { + char *database; cfg = c; stats = GNUNET_STATISTICS_create ("identity-provider", cfg); @@ -1606,10 +2384,38 @@ run (void *cls, { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns"); } - + credential_handle = GNUNET_CREDENTIAL_connect (cfg); + if (NULL == credential_handle) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential"); + } identity_handle = GNUNET_IDENTITY_connect (cfg, - &list_ego, + NULL, NULL); + stats_handle = GNUNET_STATISTICS_create ("identity-provider", + cfg); + /* Loading DB plugin */ + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "identity-provider", + "database", + &database)) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No database backend configured\n"); + GNUNET_asprintf (&db_lib_name, + "libgnunet_plugin_identity_provider_%s", + database); + TKT_database = GNUNET_PLUGIN_load (db_lib_name, + (void *) cfg); + GNUNET_free (database); + if (NULL == TKT_database) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not load database backend `%s'\n", + db_lib_name); + GNUNET_SCHEDULER_shutdown (); + return; + } if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg, @@ -1640,9 +2446,39 @@ client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx) { + struct IdpClient *idp = app_ctx; + struct AttributeIterator *ai; + struct TicketIteration *ti; + struct TicketRevocationHandle *rh; + + //TODO other operations + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client); + + while (NULL != (ai = idp->op_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->op_head, + idp->op_tail, + ai); + GNUNET_free (ai); + } + while (NULL != (rh = idp->revocation_list_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->revocation_list_head, + idp->revocation_list_tail, + rh); + cleanup_revoke_ticket_handle (rh); + } + while (NULL != (ti = idp->ticket_iter_head)) + { + GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head, + idp->ticket_iter_tail, + ti); + cleanup_ticket_iter_handle (ti); + } + GNUNET_free (idp); } @@ -1659,10 +2495,14 @@ client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq) { + struct IdpClient *idp; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client); - return client; + idp = GNUNET_new (struct IdpClient); + idp->client = client; + idp->mq = mq; + return idp; } @@ -1677,13 +2517,45 @@ GNUNET_SERVICE_MAIN &client_connect_cb, &client_disconnect_cb, NULL, - GNUNET_MQ_hd_var_size (issue_message, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, - struct IssueMessage, + GNUNET_MQ_hd_var_size (attribute_store_message, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE, + struct AttributeStoreMessage, + NULL), + GNUNET_MQ_hd_fixed_size (iteration_start, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START, + struct AttributeIterationStartMessage, + NULL), + GNUNET_MQ_hd_fixed_size (iteration_next, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT, + struct AttributeIterationNextMessage, + NULL), + GNUNET_MQ_hd_fixed_size (iteration_stop, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP, + struct AttributeIterationStopMessage, + NULL), + GNUNET_MQ_hd_var_size (issue_ticket_message, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET, + struct IssueTicketMessage, + NULL), + GNUNET_MQ_hd_var_size (consume_ticket_message, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET, + struct ConsumeTicketMessage, NULL), - GNUNET_MQ_hd_var_size (exchange_message, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, - struct ExchangeMessage, + GNUNET_MQ_hd_fixed_size (ticket_iteration_start, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START, + struct TicketIterationStartMessage, + NULL), + GNUNET_MQ_hd_fixed_size (ticket_iteration_next, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT, + struct TicketIterationNextMessage, + NULL), + GNUNET_MQ_hd_fixed_size (ticket_iteration_stop, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP, + struct TicketIterationStopMessage, + NULL), + GNUNET_MQ_hd_var_size (revoke_ticket_message, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET, + struct RevokeTicketMessage, NULL), GNUNET_MQ_handler_end()); /* end of gnunet-service-identity-provider.c */ diff --git a/src/identity-provider/identity-provider.conf b/src/identity-provider/identity-provider.conf index bac8e69ed..7ee5e50d8 100644 --- a/src/identity-provider/identity-provider.conf +++ b/src/identity-provider/identity-provider.conf @@ -10,3 +10,7 @@ UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-identity-provider.sock UNIX_MATCH_UID = NO UNIX_MATCH_GID = YES TOKEN_EXPIRATION_INTERVAL = 30 m +DATABASE = sqlite + +[identity-provider-sqlite] +FILENAME = $GNUNET_DATA_HOME/identity-provider/sqlite.db diff --git a/src/identity-provider/identity_provider.h b/src/identity-provider/identity_provider.h index 6fe6102c8..b1fe6e1fd 100644 --- a/src/identity-provider/identity_provider.h +++ b/src/identity-provider/identity_provider.h @@ -34,34 +34,157 @@ GNUNET_NETWORK_STRUCT_BEGIN /** - * The token + * Use to store an identity attribute */ -struct GNUNET_IDENTITY_PROVIDER_Token +struct AttributeStoreMessage { /** - * The JWT representation of the identity token + * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). */ - char *data; + uint32_t id GNUNET_PACKED; + + /** + * The length of the attribute + */ + uint32_t attr_len GNUNET_PACKED; + + /** + * Identity + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /* followed by the serialized attribute */ + }; /** - * The ticket + * Attribute store response message */ -struct GNUNET_IDENTITY_PROVIDER_Ticket +struct AttributeStoreResultMessage { /** - * The Base64 representation of the ticket + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * #GNUNET_SYSERR on failure, #GNUNET_OK on success + */ + int32_t op_result GNUNET_PACKED; + +}; + +/** + * Attribute is returned from the idp. + */ +struct AttributeResultMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Length of serialized attribute data + */ + uint16_t attr_len GNUNET_PACKED; + + /** + * always zero (for alignment) + */ + uint16_t reserved GNUNET_PACKED; + + /** + * The public key of the identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /* followed by: + * serialized attribute data + */ +}; + + +/** + * Start a attribute iteration for the given identity + */ +struct AttributeIterationStartMessage +{ + /** + * Message + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + +}; + + +/** + * Ask for next result of attribute iteration for the given operation + */ +struct AttributeIterationNextMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + + +/** + * Stop attribute iteration for the given operation + */ +struct AttributeIterationStopMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). */ - char *data; + uint32_t id GNUNET_PACKED; + }; /** - * Answer from service to client after issue operation + * Start a ticket iteration for the given identity */ -struct IssueResultMessage +struct TicketIterationStartMessage { /** - * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE + * Message */ struct GNUNET_MessageHeader header; @@ -70,18 +193,25 @@ struct IssueResultMessage */ uint32_t id GNUNET_PACKED; - /* followed by 0-terminated label,ticket,token */ + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + /** + * Identity is audience or issuer + */ + uint32_t is_audience GNUNET_PACKED; }; /** - * Ticket exchange message. + * Ask for next result of ticket iteration for the given operation */ -struct ExchangeResultMessage +struct TicketIterationNextMessage { /** - * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT */ struct GNUNET_MessageHeader header; @@ -90,25 +220,35 @@ struct ExchangeResultMessage */ uint32_t id GNUNET_PACKED; +}; + + +/** + * Stop ticket iteration for the given operation + */ +struct TicketIterationStopMessage +{ /** - * Nonce found in ticket. NBO - * 0 on error. + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP */ - uint64_t ticket_nonce GNUNET_PACKED; + struct GNUNET_MessageHeader header; - /* followed by 0-terminated token */ + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; }; /** - * Client requests IdP to issue token. + * Ticket issue message */ -struct IssueMessage +struct IssueTicketMessage { /** - * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET */ struct GNUNET_MessageHeader header; @@ -117,40 +257,98 @@ struct IssueMessage */ uint32_t id GNUNET_PACKED; + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; /** - * Issuer identity private key + * Requesting party. */ - struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key; + struct GNUNET_CRYPTO_EcdsaPublicKey rp; /** - * Audience public key + * length of serialized attribute list */ - struct GNUNET_CRYPTO_EcdsaPublicKey aud_key; + uint32_t attr_len GNUNET_PACKED; + //Followed by a serialized attribute list +}; + +/** + * Ticket revoke message + */ +struct RevokeTicketMessage +{ /** - * Nonce + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET */ - uint64_t nonce; + struct GNUNET_MessageHeader header; /** - * Expiration of token in NBO. + * Unique identifier for this request (for key collisions). */ - struct GNUNET_TIME_AbsoluteNBO expiration; + uint32_t id GNUNET_PACKED; + /** + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; - /* followed by 0-terminated comma-separated scope list */ + /** + * length of serialized attribute list + */ + uint32_t attrs_len GNUNET_PACKED; + //Followed by a ticket and serialized attribute list +}; + +/** + * Ticket revoke message + */ +struct RevokeTicketResultMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Revocation result + */ + uint32_t success GNUNET_PACKED; }; /** - * Use to exchange a ticket for a token + * Ticket result message */ -struct ExchangeMessage +struct TicketResultMessage { /** - * Type: #GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + +}; + +/** + * Ticket consume message + */ +struct ConsumeTicketMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET */ struct GNUNET_MessageHeader header; @@ -160,15 +358,50 @@ struct ExchangeMessage uint32_t id GNUNET_PACKED; /** - * Audience identity private key + * Identity. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + //Followed by a serialized ticket +}; + +/** + * Attribute list is returned from the idp. + */ +struct ConsumeTicketResultMessage +{ + /** + * Message header + */ + struct GNUNET_MessageHeader header; + + /** + * Unique identifier for this request (for key collisions). + */ + uint32_t id GNUNET_PACKED; + + /** + * Length of serialized attribute data */ - struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey; + uint16_t attrs_len GNUNET_PACKED; - /* followed by 0-terminated ticket string */ + /** + * always zero (for alignment) + */ + uint16_t reserved GNUNET_PACKED; + /** + * The public key of the identity. + */ + struct GNUNET_CRYPTO_EcdsaPublicKey identity; + + /* followed by: + * serialized attributes data + */ }; + GNUNET_NETWORK_STRUCT_END #endif diff --git a/src/identity-provider/identity_provider_api.c b/src/identity-provider/identity_provider_api.c index 845d1f753..d0ece80fe 100644 --- a/src/identity-provider/identity_provider_api.c +++ b/src/identity-provider/identity_provider_api.c @@ -29,12 +29,12 @@ #include "gnunet_protocols.h" #include "gnunet_mq_lib.h" #include "gnunet_identity_provider_service.h" +#include "gnunet_identity_attribute_lib.h" #include "identity_provider.h" #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__) - /** * Handle for an operation with the service. */ @@ -63,16 +63,24 @@ struct GNUNET_IDENTITY_PROVIDER_Operation const struct GNUNET_MessageHeader *msg; /** - * Continuation to invoke with the result of the transmission; @e cb - * will be NULL in this case. + * Continuation to invoke after attribute store call + */ + GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus as_cb; + + /** + * Attribute result callback + */ + GNUNET_IDENTITY_PROVIDER_AttributeResult ar_cb; + + /** + * Revocation result callback */ - GNUNET_IDENTITY_PROVIDER_ExchangeCallback ex_cb; + GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus rvk_cb; /** - * Continuation to invoke with the result of the transmission for - * 'issue' operations (@e cont will be NULL in this case). + * Ticket result callback */ - GNUNET_IDENTITY_PROVIDER_IssueCallback iss_cb; + GNUNET_IDENTITY_PROVIDER_TicketCallback tr_cb; /** * Envelope with the message for this queue entry. @@ -91,6 +99,140 @@ struct GNUNET_IDENTITY_PROVIDER_Operation }; +/** + * Handle for a ticket iterator operation + */ +struct GNUNET_IDENTITY_PROVIDER_TicketIterator +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *prev; + + /** + * Main handle to access the idp. + */ + struct GNUNET_IDENTITY_PROVIDER_Handle *h; + + /** + * Function to call on completion. + */ + GNUNET_SCHEDULER_TaskCallback finish_cb; + + /** + * Closure for @e error_cb. + */ + void *finish_cb_cls; + + /** + * The continuation to call with the results + */ + GNUNET_IDENTITY_PROVIDER_TicketCallback tr_cb; + + /** + * Closure for @e tr_cb. + */ + void *cls; + + /** + * Function to call on errors. + */ + GNUNET_SCHEDULER_TaskCallback error_cb; + + /** + * Closure for @e error_cb. + */ + void *error_cb_cls; + + /** + * Envelope of the message to send to the service, if not yet + * sent. + */ + struct GNUNET_MQ_Envelope *env; + + /** + * The operation id this zone iteration operation has + */ + uint32_t r_id; + +}; + + +/** + * Handle for a attribute iterator operation + */ +struct GNUNET_IDENTITY_PROVIDER_AttributeIterator +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *prev; + + /** + * Main handle to access the idp. + */ + struct GNUNET_IDENTITY_PROVIDER_Handle *h; + + /** + * Function to call on completion. + */ + GNUNET_SCHEDULER_TaskCallback finish_cb; + + /** + * Closure for @e error_cb. + */ + void *finish_cb_cls; + + /** + * The continuation to call with the results + */ + GNUNET_IDENTITY_PROVIDER_AttributeResult proc; + + /** + * Closure for @e proc. + */ + void *proc_cls; + + /** + * Function to call on errors. + */ + GNUNET_SCHEDULER_TaskCallback error_cb; + + /** + * Closure for @e error_cb. + */ + void *error_cb_cls; + + /** + * Envelope of the message to send to the service, if not yet + * sent. + */ + struct GNUNET_MQ_Envelope *env; + + /** + * Private key of the zone. + */ + struct GNUNET_CRYPTO_EcdsaPrivateKey identity; + + /** + * The operation id this zone iteration operation has + */ + uint32_t r_id; + +}; + /** * Handle for the service. @@ -123,6 +265,27 @@ struct GNUNET_IDENTITY_PROVIDER_Handle struct GNUNET_IDENTITY_PROVIDER_Operation *op_tail; /** + * Head of active iterations + */ + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it_head; + + /** + * Tail of active iterations + */ + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it_tail; + + /** + * Head of active iterations + */ + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it_head; + + /** + * Tail of active iterations + */ + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it_tail; + + + /** * Currently pending transmission request, or NULL for none. */ struct GNUNET_CLIENT_TransmitHandle *th; @@ -154,14 +317,13 @@ struct GNUNET_IDENTITY_PROVIDER_Handle }; - /** * Try again to connect to the service. * - * @param cls handle to the service. + * @param h handle to the identity provider service. */ static void -reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle); +reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h); /** * Reconnect @@ -181,7 +343,7 @@ reconnect_task (void *cls) /** * Disconnect from service and then reconnect. * - * @param handle our handle + * @param handle our service */ static void force_reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle) @@ -197,6 +359,26 @@ force_reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *handle) } /** + * Free @a it. + * + * @param it entry to free + */ +static void +free_it (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it) +{ + struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; + + GNUNET_CONTAINER_DLL_remove (h->it_head, + h->it_tail, + it); + if (NULL != it->env) + GNUNET_MQ_discard (it->env); + GNUNET_free (it); +} + + + +/** * Generic error handler, called with the appropriate error code and * the same closure specified at the creation of the message queue. * Not every message queue implementation supports an error handler. @@ -213,22 +395,68 @@ mq_error_handler (void *cls, } /** - * Check validity of message received from the service + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE_RESPONSE + * + * @param cls + * @param msg the message we received + */ +static void +handle_attribute_store_response (void *cls, + const struct AttributeStoreResultMessage *msg) +{ + struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + uint32_t r_id = ntohl (msg->id); + int res; + const char *emsg; + + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if (NULL == op) + return; + + res = ntohl (msg->op_result); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received ATTRIBUTE_STORE_RESPONSE with result %d\n", + res); + + /* TODO: add actual error message to response... */ + if (GNUNET_SYSERR == res) + emsg = _("failed to store record\n"); + else + emsg = NULL; + if (NULL != op->as_cb) + op->as_cb (op->cls, + res, + emsg); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + GNUNET_free (op); + +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT * - * @param cls the `struct GNUNET_IDENTITY_PROVIDER_Handle *` - * @param result_msg the incoming message + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int -check_exchange_result (void *cls, - const struct ExchangeResultMessage *erm) +check_consume_ticket_result (void *cls, + const struct ConsumeTicketResultMessage *msg) { - char *str; - size_t size = ntohs (erm->header.size) - sizeof (*erm); - + size_t msg_len; + size_t attrs_len; - str = (char *) &erm[1]; - if ( (size > sizeof (struct ExchangeResultMessage)) && - ('\0' != str[size - sizeof (struct ExchangeResultMessage) - 1]) ) + msg_len = ntohs (msg->header.size); + attrs_len = ntohs (msg->attrs_len); + if (msg_len != sizeof (struct ConsumeTicketResultMessage) + attrs_len) { GNUNET_break (0); return GNUNET_SYSERR; @@ -238,20 +466,85 @@ check_exchange_result (void *cls, /** - * Check validity of message received from the service + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_consume_ticket_result (void *cls, + const struct ConsumeTicketResultMessage *msg) +{ + struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + size_t attrs_len; + uint32_t r_id = ntohl (msg->id); + + attrs_len = ntohs (msg->attrs_len); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing attribute result.\n"); + + + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if (NULL == op) + return; + + { + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize ((char*)&msg[1], + attrs_len); + if (NULL != op->ar_cb) + { + if (NULL == attrs) + { + op->ar_cb (op->cls, + &msg->identity, + NULL); + } + else + { + for (le = attrs->list_head; NULL != le; le = le->next) + op->ar_cb (op->cls, + &msg->identity, + le->claim); + GNUNET_IDENTITY_ATTRIBUTE_list_destroy (attrs); + } + } + op->ar_cb (op->cls, + NULL, + NULL); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + GNUNET_free (op); + return; + } + GNUNET_assert (0); +} + + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT * - * @param cls the `struct GNUNET_IDENTITY_PROVIDER_Handle *` - * @param result_msg the incoming message + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ static int -check_result (void *cls, - const struct IssueResultMessage *irm) +check_attribute_result (void *cls, + const struct AttributeResultMessage *msg) { - char *str; - size_t size = ntohs (irm->header.size) - sizeof (*irm); - str = (char*) &irm[1]; - if ( (size > sizeof (struct IssueResultMessage)) && - ('\0' != str[size - sizeof (struct IssueResultMessage) - 1]) ) + size_t msg_len; + size_t attr_len; + + msg_len = ntohs (msg->header.size); + attr_len = ntohs (msg->attr_len); + if (msg_len != sizeof (struct AttributeResultMessage) + attr_len) { GNUNET_break (0); return GNUNET_SYSERR; @@ -259,119 +552,254 @@ check_result (void *cls, return GNUNET_OK; } + /** - * Handler for messages received from the GNS service + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT * - * @param cls the `struct GNUNET_GNS_Handle *` - * @param loookup_msg the incoming message + * @param cls + * @param msg the message we received */ static void -handle_exchange_result (void *cls, - const struct ExchangeResultMessage *erm) +handle_attribute_result (void *cls, + const struct AttributeResultMessage *msg) { - struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls; + static struct GNUNET_CRYPTO_EcdsaPrivateKey identity_dummy; + struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it; struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct GNUNET_IDENTITY_PROVIDER_Token token; - uint64_t ticket_nonce; - uint32_t r_id = ntohl (erm->id); - char *str; - - for (op = handle->op_head; NULL != op; op = op->next) + size_t attr_len; + uint32_t r_id = ntohl (msg->id); + + attr_len = ntohs (msg->attr_len); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing attribute result.\n"); + + + for (it = h->it_head; NULL != it; it = it->next) + if (it->r_id == r_id) + break; + for (op = h->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; - if (NULL == op) + if ((NULL == it) && (NULL == op)) return; - str = GNUNET_strdup ((char*)&erm[1]); - op = handle->op_head; - GNUNET_CONTAINER_DLL_remove (handle->op_head, - handle->op_tail, - op); - token.data = str; - ticket_nonce = ntohl (erm->ticket_nonce); - if (NULL != op->ex_cb) - op->ex_cb (op->cls, &token, ticket_nonce); - GNUNET_free (str); - GNUNET_free (op); + if ( (0 == (memcmp (&msg->identity, + &identity_dummy, + sizeof (identity_dummy)))) ) + { + if ((NULL == it) && (NULL == op)) + { + GNUNET_break (0); + force_reconnect (h); + return; + } + if (NULL != it) + { + if (NULL != it->finish_cb) + it->finish_cb (it->finish_cb_cls); + free_it (it); + } + if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, + NULL, + NULL); + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + GNUNET_free (op); + + } + return; + } + + { + struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr; + attr = GNUNET_IDENTITY_ATTRIBUTE_deserialize ((char*)&msg[1], + attr_len); + if (NULL != it) + { + if (NULL != it->proc) + it->proc (it->proc_cls, + &msg->identity, + attr); + } else if (NULL != op) + { + if (NULL != op->ar_cb) + op->ar_cb (op->cls, + &msg->identity, + attr); + + } + GNUNET_free (attr); + return; + } + GNUNET_assert (0); +} + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT + * + * @param cls + * @param msg the message we received + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static int +check_ticket_result (void *cls, + const struct TicketResultMessage *msg) +{ + size_t msg_len; + + msg_len = ntohs (msg->header.size); + if (msg_len < sizeof (struct TicketResultMessage)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; } + + /** - * Handler for messages received from the GNS service + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT * - * @param cls the `struct GNUNET_GNS_Handle *` - * @param loookup_msg the incoming message + * @param cls + * @param msg the message we received */ static void -handle_result (void *cls, - const struct IssueResultMessage *irm) +handle_ticket_result (void *cls, + const struct TicketResultMessage *msg) { struct GNUNET_IDENTITY_PROVIDER_Handle *handle = cls; struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct GNUNET_IDENTITY_PROVIDER_Token token; - struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; - uint32_t r_id = ntohl (irm->id); - char *str; - char *label_str; - char *ticket_str; - char *token_str; + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it; + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; + uint32_t r_id = ntohl (msg->id); + size_t msg_len; for (op = handle->op_head; NULL != op; op = op->next) if (op->r_id == r_id) break; - if (NULL == op) + for (it = handle->ticket_it_head; NULL != it; it = it->next) + if (it->r_id == r_id) + break; + if ((NULL == op) && (NULL == it)) return; - str = GNUNET_strdup ((char*)&irm[1]); - label_str = strtok (str, ","); - - if (NULL == label_str) + msg_len = ntohs (msg->header.size); + if (NULL != op) { - GNUNET_free (str); - GNUNET_break (0); + GNUNET_CONTAINER_DLL_remove (handle->op_head, + handle->op_tail, + op); + if (msg_len == sizeof (struct TicketResultMessage)) + { + if (NULL != op->tr_cb) + op->tr_cb (op->cls, NULL); + } else { + ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1]; + if (NULL != op->tr_cb) + op->tr_cb (op->cls, ticket); + } + GNUNET_free (op); return; - } - ticket_str = strtok (NULL, ","); - if (NULL == ticket_str) - { - GNUNET_free (str); - GNUNET_break (0); + } else if (NULL != it) { + if (msg_len == sizeof (struct TicketResultMessage)) + { + if (NULL != it->tr_cb) + GNUNET_CONTAINER_DLL_remove (handle->ticket_it_head, + handle->ticket_it_tail, + it); + it->finish_cb (it->finish_cb_cls); + GNUNET_free (it); + } else { + ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket *)&msg[1]; + if (NULL != it->tr_cb) + it->tr_cb (it->cls, ticket); + } return; } - token_str = strtok (NULL, ","); - if (NULL == token_str) + GNUNET_break (0); +} + +/** + * Handle an incoming message of type + * #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT + * + * @param cls + * @param msg the message we received + */ +static void +handle_revoke_ticket_result (void *cls, + const struct RevokeTicketResultMessage *msg) +{ + struct GNUNET_IDENTITY_PROVIDER_Handle *h = cls; + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + uint32_t r_id = ntohl (msg->id); + int32_t success; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Processing revocation result.\n"); + + + for (op = h->op_head; NULL != op; op = op->next) + if (op->r_id == r_id) + break; + if (NULL == op) + return; + success = ntohl (msg->success); { - GNUNET_free (str); - GNUNET_break (0); + if (NULL != op->rvk_cb) + { + op->rvk_cb (op->cls, + success, + NULL); + } + GNUNET_CONTAINER_DLL_remove (h->op_head, + h->op_tail, + op); + GNUNET_free (op); return; } - GNUNET_CONTAINER_DLL_remove (handle->op_head, - handle->op_tail, - op); - ticket.data = ticket_str; - token.data = token_str; - if (NULL != op->iss_cb) - op->iss_cb (op->cls, label_str, &ticket, &token); - GNUNET_free (str); - GNUNET_free (op); - + GNUNET_assert (0); } + + /** * Try again to connect to the service. * - * @param cls handle to the identity provider service. + * @param h handle to the identity provider service. */ static void reconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h) { struct GNUNET_MQ_MessageHandler handlers[] = { - GNUNET_MQ_hd_var_size (result, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT, - struct IssueResultMessage, + GNUNET_MQ_hd_fixed_size (attribute_store_response, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE_RESPONSE, + struct AttributeStoreResultMessage, + h), + GNUNET_MQ_hd_var_size (attribute_result, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_RESULT, + struct AttributeResultMessage, h), - GNUNET_MQ_hd_var_size (exchange_result, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT, - struct ExchangeResultMessage, + GNUNET_MQ_hd_var_size (ticket_result, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT, + struct TicketResultMessage, h), + GNUNET_MQ_hd_var_size (consume_ticket_result, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET_RESULT, + struct ConsumeTicketResultMessage, + h), + GNUNET_MQ_hd_fixed_size (revoke_ticket_result, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET_RESULT, + struct RevokeTicketResultMessage, + h), GNUNET_MQ_handler_end () }; struct GNUNET_IDENTITY_PROVIDER_Operation *op; @@ -417,111 +845,6 @@ GNUNET_IDENTITY_PROVIDER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) /** - * Issue an identity token - * - * @param id identity service to query - * @param service_name for which service is an identity wanted - * @param cb function to call with the result (will only be called once) - * @param cb_cls closure for @a cb - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_issue_token (struct GNUNET_IDENTITY_PROVIDER_Handle *id, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - const char* scopes, - struct GNUNET_TIME_Absolute expiration, - uint64_t nonce, - GNUNET_IDENTITY_PROVIDER_IssueCallback cb, - void *cb_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct IssueMessage *im; - size_t slen; - - slen = strlen (scopes) + 1; - if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct IssueMessage)) - { - GNUNET_break (0); - return NULL; - } - op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); - op->h = id; - op->iss_cb = cb; - op->cls = cb_cls; - op->r_id = id->r_id_gen++; - op->env = GNUNET_MQ_msg_extra (im, - slen, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE); - im->id = op->r_id; - im->iss_key = *iss_key; - im->aud_key = *aud_key; - im->nonce = htonl (nonce); - im->expiration = GNUNET_TIME_absolute_hton (expiration); - GNUNET_memcpy (&im[1], scopes, slen); - GNUNET_CONTAINER_DLL_insert_tail (id->op_head, - id->op_tail, - op); - if (NULL != id->mq) - GNUNET_MQ_send_copy (id->mq, - op->env); - return op; -} - - -/** - * Exchange a token ticket for a token - * - * @param id identity provider service - * @param ticket ticket to exchange - * @param cont function to call once the operation finished - * @param cont_cls closure for @a cont - * @return handle to abort the operation - */ -struct GNUNET_IDENTITY_PROVIDER_Operation * -GNUNET_IDENTITY_PROVIDER_exchange_ticket (struct GNUNET_IDENTITY_PROVIDER_Handle *id, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *aud_privkey, - GNUNET_IDENTITY_PROVIDER_ExchangeCallback cont, - void *cont_cls) -{ - struct GNUNET_IDENTITY_PROVIDER_Operation *op; - struct ExchangeMessage *em; - size_t slen; - char *ticket_str; - - ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket); - - slen = strlen (ticket_str) + 1; - if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct ExchangeMessage)) - { - GNUNET_free (ticket_str); - GNUNET_break (0); - return NULL; - } - op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); - op->h = id; - op->ex_cb = cont; - op->cls = cont_cls; - op->r_id = id->r_id_gen++; - op->env = GNUNET_MQ_msg_extra (em, - slen, - GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE); - em->aud_privkey = *aud_privkey; - em->id = htonl (op->r_id); - GNUNET_memcpy (&em[1], ticket_str, slen); - GNUNET_free (ticket_str); - GNUNET_CONTAINER_DLL_insert_tail (id->op_head, - id->op_tail, - op); - if (NULL != id->mq) - GNUNET_MQ_send_copy (id->mq, - op->env); - return op; -} - - -/** * Cancel an operation. Note that the operation MAY still * be executed; this merely cancels the continuation; if the request * was already transmitted, the service may still choose to complete @@ -566,80 +889,482 @@ GNUNET_IDENTITY_PROVIDER_disconnect (struct GNUNET_IDENTITY_PROVIDER_Handle *h) } /** - * Convenience API + * Store an attribute. If the attribute is already present, + * it is replaced with the new attribute. + * + * @param h handle to the identity provider + * @param pkey private key of the identity + * @param attr the attribute value + * @param cont continuation to call when done + * @param cont_cls closure for @a cont + * @return handle to abort the request */ +struct GNUNET_IDENTITY_PROVIDER_Operation * +GNUNET_IDENTITY_PROVIDER_attribute_store (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey, + const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr, + GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cont, + void *cont_cls) +{ + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + struct AttributeStoreMessage *sam; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); + op->h = h; + op->as_cb = cont; + op->cls = cont_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + attr_len = GNUNET_IDENTITY_ATTRIBUTE_serialize_get_size (attr); + op->env = GNUNET_MQ_msg_extra (sam, + attr_len, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_STORE); + sam->identity = *pkey; + sam->id = htonl (op->r_id); + + GNUNET_IDENTITY_ATTRIBUTE_serialize (attr, + (char*)&sam[1]); + + sam->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, + op->env); + return op; + +} + + +/** + * List all attributes for a local identity. + * This MUST lock the `struct GNUNET_IDENTITY_PROVIDER_Handle` + * for any other calls than #GNUNET_IDENTITY_PROVIDER_get_attributes_next() and + * #GNUNET_IDENTITY_PROVIDER_get_attributes_stop. @a proc will be called once + * immediately, and then again after + * #GNUNET_IDENTITY_PROVIDER_get_attributes_next() is invoked. + * + * On error (disconnect), @a error_cb will be invoked. + * On normal completion, @a finish_cb proc will be + * invoked. + * + * @param h handle to the idp + * @param identity identity to access + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each attribute; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration + */ +struct GNUNET_IDENTITY_PROVIDER_AttributeIterator * +GNUNET_IDENTITY_PROVIDER_get_attributes_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_IDENTITY_PROVIDER_AttributeResult proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) +{ + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it; + struct GNUNET_MQ_Envelope *env; + struct AttributeIterationStartMessage *msg; + uint32_t rid; + + rid = h->r_id_gen++; + it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->proc = proc; + it->proc_cls = proc_cls; + it->r_id = rid; + it->identity = *identity; + GNUNET_CONTAINER_DLL_insert_tail (h->it_head, + h->it_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_START); + msg->id = htonl (rid); + msg->identity = *identity; + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return it; +} /** - * Destroy token + * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_get_attributes_start + * for the next record. * - * @param token the token + * @param it the iterator */ void -GNUNET_IDENTITY_PROVIDER_token_destroy(struct GNUNET_IDENTITY_PROVIDER_Token *token) +GNUNET_IDENTITY_PROVIDER_get_attributes_next (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it) +{ + struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; + struct AttributeIterationNextMessage *msg; + struct GNUNET_MQ_Envelope *env; + + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_NEXT); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); +} + + +/** + * Stops iteration and releases the idp handle for further calls. Must + * be called on any iteration that has not yet completed prior to calling + * #GNUNET_IDENTITY_PROVIDER_disconnect. + * + * @param it the iterator + */ +void +GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *it) +{ + struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; + struct GNUNET_MQ_Envelope *env; + struct AttributeIterationStopMessage *msg; + + if (NULL != h->mq) + { + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ATTRIBUTE_ITERATION_STOP); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); + } + free_it (it); +} + + +/** TODO + * Issues a ticket to another identity. The identity may use + * @GNUNET_IDENTITY_PROVIDER_authorization_ticket_consume to consume the ticket + * and retrieve the attributes specified in the AttributeList. + * + * @param h the identity provider to use + * @param iss the issuing identity + * @param rp the subject of the ticket (the relying party) + * @param attrs the attributes that the relying party is given access to + * @param cb the callback + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_IDENTITY_PROVIDER_Operation * +GNUNET_IDENTITY_PROVIDER_ticket_issue (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *iss, + const struct GNUNET_CRYPTO_EcdsaPublicKey *rp, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, + GNUNET_IDENTITY_PROVIDER_TicketCallback cb, + void *cb_cls) +{ + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + struct IssueTicketMessage *tim; + size_t attr_len; + + op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); + op->h = h; + op->tr_cb = cb; + op->cls = cb_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + attr_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs); + op->env = GNUNET_MQ_msg_extra (tim, + attr_len, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_TICKET); + tim->identity = *iss; + tim->rp = *rp; + tim->id = htonl (op->r_id); + + GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs, + (char*)&tim[1]); + + tim->attr_len = htons (attr_len); + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, + op->env); + return op; +} + +/** + * Consumes an issued ticket. The ticket is persisted + * and used to retrieve identity information from the issuer + * + * @param h the identity provider to use + * @param identity the identity that is the subject of the issued ticket (the relying party) + * @param ticket the issued ticket to consume + * @param cb the callback to call + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_IDENTITY_PROVIDER_Operation * +GNUNET_IDENTITY_PROVIDER_ticket_consume (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + GNUNET_IDENTITY_PROVIDER_AttributeResult cb, + void *cb_cls) { - GNUNET_assert (NULL != token); - if (NULL != token->data) - GNUNET_free (token->data); - GNUNET_free (token); + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + struct ConsumeTicketMessage *ctm; + + op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); + op->h = h; + op->ar_cb = cb; + op->cls = cb_cls; + op->r_id = h->r_id_gen++; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + op->env = GNUNET_MQ_msg_extra (ctm, + sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket), + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET); + ctm->identity = *identity; + ctm->id = htonl (op->r_id); + + GNUNET_memcpy ((char*)&ctm[1], + ticket, + sizeof (const struct GNUNET_IDENTITY_PROVIDER_Ticket)); + + if (NULL != h->mq) + GNUNET_MQ_send_copy (h->mq, + op->env); + return op; + } + /** - * Returns string representation of token. A JSON-Web-Token. + * Lists all tickets that have been issued to remote + * identites (relying parties) * - * @param token the token - * @return The JWT (must be freed) + * @param h the identity provider to use + * @param identity the issuing identity + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each ticket; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration */ -char * -GNUNET_IDENTITY_PROVIDER_token_to_string (const struct GNUNET_IDENTITY_PROVIDER_Token *token) +struct GNUNET_IDENTITY_PROVIDER_TicketIterator * +GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_IDENTITY_PROVIDER_TicketCallback proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) { - return GNUNET_strdup (token->data); + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it; + struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub; + struct GNUNET_MQ_Envelope *env; + struct TicketIterationStartMessage *msg; + uint32_t rid; + + GNUNET_CRYPTO_ecdsa_key_get_public (identity, + &identity_pub); + rid = h->r_id_gen++; + it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->tr_cb = proc; + it->cls = proc_cls; + it->r_id = rid; + GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, + h->ticket_it_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START); + msg->id = htonl (rid); + msg->identity = identity_pub; + msg->is_audience = htonl (GNUNET_NO); + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return it; + } + /** - * Returns string representation of ticket. Base64-Encoded + * Lists all tickets that have been issued to remote + * identites (relying parties) * - * @param ticket the ticket - * @return the Base64-Encoded ticket + * @param h the identity provider to use + * @param identity the issuing identity + * @param error_cb function to call on error (i.e. disconnect), + * the handle is afterwards invalid + * @param error_cb_cls closure for @a error_cb + * @param proc function to call on each ticket; it + * will be called repeatedly with a value (if available) + * @param proc_cls closure for @a proc + * @param finish_cb function to call on completion + * the handle is afterwards invalid + * @param finish_cb_cls closure for @a finish_cb + * @return an iterator handle to use for iteration */ -char * -GNUNET_IDENTITY_PROVIDER_ticket_to_string (const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) +struct GNUNET_IDENTITY_PROVIDER_TicketIterator * +GNUNET_IDENTITY_PROVIDER_ticket_iteration_start_rp (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + GNUNET_SCHEDULER_TaskCallback error_cb, + void *error_cb_cls, + GNUNET_IDENTITY_PROVIDER_TicketCallback proc, + void *proc_cls, + GNUNET_SCHEDULER_TaskCallback finish_cb, + void *finish_cb_cls) { - return GNUNET_strdup (ticket->data); + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it; + struct GNUNET_MQ_Envelope *env; + struct TicketIterationStartMessage *msg; + uint32_t rid; + + rid = h->r_id_gen++; + it = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_TicketIterator); + it->h = h; + it->error_cb = error_cb; + it->error_cb_cls = error_cb_cls; + it->finish_cb = finish_cb; + it->finish_cb_cls = finish_cb_cls; + it->tr_cb = proc; + it->cls = proc_cls; + it->r_id = rid; + GNUNET_CONTAINER_DLL_insert_tail (h->ticket_it_head, + h->ticket_it_tail, + it); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START); + msg->id = htonl (rid); + msg->identity = *identity; + msg->is_audience = htonl (GNUNET_YES); + if (NULL == h->mq) + it->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return it; + + } /** - * Created a ticket from a string (Base64 encoded ticket) + * Calls the record processor specified in #GNUNET_IDENTITY_PROVIDER_ticket_iteration_start + * for the next record. * - * @param input Base64 encoded ticket - * @param ticket pointer where the ticket is stored - * @return GNUNET_OK + * @param it the iterator */ -int -GNUNET_IDENTITY_PROVIDER_string_to_ticket (const char* input, - struct GNUNET_IDENTITY_PROVIDER_Ticket **ticket) +void +GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it) { - *ticket = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); - (*ticket)->data = GNUNET_strdup (input); - return GNUNET_OK; + struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; + struct TicketIterationNextMessage *msg; + struct GNUNET_MQ_Envelope *env; + + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); } /** - * Destroys a ticket + * Stops iteration and releases the idp handle for further calls. Must + * be called on any iteration that has not yet completed prior to calling + * #GNUNET_IDENTITY_PROVIDER_disconnect. * - * @param ticket the ticket to destroy + * @param it the iterator */ void -GNUNET_IDENTITY_PROVIDER_ticket_destroy(struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) +GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (struct GNUNET_IDENTITY_PROVIDER_TicketIterator *it) { - GNUNET_assert (NULL != ticket); - if (NULL != ticket->data) - GNUNET_free (ticket->data); - GNUNET_free (ticket); + struct GNUNET_IDENTITY_PROVIDER_Handle *h = it->h; + struct GNUNET_MQ_Envelope *env; + struct TicketIterationStopMessage *msg; + + if (NULL != h->mq) + { + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP); + msg->id = htonl (it->r_id); + GNUNET_MQ_send (h->mq, + env); + } + GNUNET_free (it); } +/** + * Revoked an issued ticket. The relying party will be unable to retrieve + * updated attributes. + * + * @param h the identity provider to use + * @param identity the issuing identity + * @param ticket the ticket to revoke + * @param cb the callback + * @param cb_cls the callback closure + * @return handle to abort the operation + */ +struct GNUNET_IDENTITY_PROVIDER_Operation * +GNUNET_IDENTITY_PROVIDER_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Handle *h, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + GNUNET_IDENTITY_PROVIDER_ContinuationWithStatus cb, + void *cb_cls) +{ + struct GNUNET_IDENTITY_PROVIDER_Operation *op; + struct GNUNET_MQ_Envelope *env; + struct RevokeTicketMessage *msg; + uint32_t rid; + rid = h->r_id_gen++; + op = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_Operation); + op->h = h; + op->rvk_cb = cb; + op->cls = cb_cls; + op->r_id = rid; + GNUNET_CONTAINER_DLL_insert_tail (h->op_head, + h->op_tail, + op); + env = GNUNET_MQ_msg_extra (msg, + sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket), + GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_REVOKE_TICKET); + msg->id = htonl (rid); + msg->identity = *identity; + memcpy (&msg[1], + ticket, + sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket)); + if (NULL == h->mq) + op->env = env; + else + GNUNET_MQ_send (h->mq, + env); + return op; +} diff --git a/src/identity-provider/identity_token.c b/src/identity-provider/identity_token.c deleted file mode 100644 index 31249840b..000000000 --- a/src/identity-provider/identity_token.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - This file is part of GNUnet - Copyright (C) 2010-2015 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ - -/** - * @file identity-provider/identity_token.c - * @brief helper library to manage identity tokens - * @author Martin Schanzenbach - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_signatures.h" -#include "identity_token.h" -#include <jansson.h> -#include <inttypes.h> - -#define JWT_ALG "alg" - -#define JWT_ALG_VALUE "ED512" - -#define JWT_TYP "typ" - -#define JWT_TYP_VALUE "jwt" - -/** - * Crypto helper functions - */ - -static int -create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash, - struct GNUNET_CRYPTO_SymmetricSessionKey *skey, - struct GNUNET_CRYPTO_SymmetricInitializationVector *iv) -{ - struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str; - - GNUNET_CRYPTO_hash_to_enc (new_key_hash, - &new_key_hash_str); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str); - static const char ctx_key[] = "gnuid-aes-ctx-key"; - GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey), - new_key_hash, sizeof (struct GNUNET_HashCode), - ctx_key, strlen (ctx_key), - NULL, 0); - static const char ctx_iv[] = "gnuid-aes-ctx-iv"; - GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector), - new_key_hash, sizeof (struct GNUNET_HashCode), - ctx_iv, strlen (ctx_iv), - NULL, 0); - return GNUNET_OK; -} - - - -/** - * Decrypts data part from a token code - */ -static int -decrypt_str_ecdhe (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - const struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key, - const char *cyphertext, - size_t cyphertext_len, - char **result_str) -{ - struct GNUNET_HashCode new_key_hash; - struct GNUNET_CRYPTO_SymmetricSessionKey enc_key; - struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv; - - char *str_buf = GNUNET_malloc (cyphertext_len); - size_t str_size; - - //Calculate symmetric key from ecdh parameters - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_ecdh (priv_key, - ecdh_key, - &new_key_hash)); - - create_sym_key_from_ecdh (&new_key_hash, - &enc_key, - &enc_iv); - - str_size = GNUNET_CRYPTO_symmetric_decrypt (cyphertext, - cyphertext_len, - &enc_key, - &enc_iv, - str_buf); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Decrypted bytes: %zd Expected bytes: %zd\n", - str_size, - cyphertext_len); - if (-1 == str_size) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH invalid\n"); - GNUNET_free (str_buf); - return GNUNET_SYSERR; - } - *result_str = GNUNET_malloc (str_size+1); - GNUNET_memcpy (*result_str, str_buf, str_size); - (*result_str)[str_size] = '\0'; - GNUNET_free (str_buf); - return GNUNET_OK; - -} - -/** - * Decrypt string using pubkey and ECDHE -*/ -static int -decrypt_str_ecdhe2 (const struct GNUNET_CRYPTO_EcdhePrivateKey *ecdh_privkey, - const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - const char *ciphertext, - size_t ciphertext_len, - char **plaintext) -{ - struct GNUNET_CRYPTO_SymmetricSessionKey skey; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct GNUNET_HashCode new_key_hash; - - //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt - *plaintext = GNUNET_malloc (ciphertext_len); - - // Derived key K = H(eB) - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (ecdh_privkey, - aud_key, - &new_key_hash)); - create_sym_key_from_ecdh(&new_key_hash, &skey, &iv); - GNUNET_CRYPTO_symmetric_decrypt (ciphertext, - ciphertext_len, - &skey, &iv, - *plaintext); - return GNUNET_OK; -} - - -/** - * Encrypt string using pubkey and ECDHE - * Returns ECDHE pubkey to be used for decryption - */ -static int -encrypt_str_ecdhe (const char *plaintext, - const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key, - char **cyphertext, - struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey, - struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_pubkey) -{ - struct GNUNET_CRYPTO_SymmetricSessionKey skey; - struct GNUNET_CRYPTO_SymmetricInitializationVector iv; - struct GNUNET_HashCode new_key_hash; - ssize_t enc_size; - - // ECDH keypair E = eG - *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create(); - GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey, - ecdh_pubkey); - - //This is true see documentation for GNUNET_CRYPTO_symmetric_encrypt - *cyphertext = GNUNET_malloc (strlen (plaintext)); - - // Derived key K = H(eB) - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey, - pub_key, - &new_key_hash)); - create_sym_key_from_ecdh(&new_key_hash, &skey, &iv); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting string %s\n (len=%zd)", - plaintext, - strlen (plaintext)); - enc_size = GNUNET_CRYPTO_symmetric_encrypt (plaintext, - strlen (plaintext), - &skey, &iv, - *cyphertext); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypted (len=%zd)", enc_size); - return GNUNET_OK; -} - - -/** - * Identity Token API - */ - - -/** - * Create an Identity Token - * - * @param type the JSON API resource type - * @param id the JSON API resource id - * @return a new JSON API resource or NULL on error. - */ -struct IdentityToken* -token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey* iss, - const struct GNUNET_CRYPTO_EcdsaPublicKey* aud) -{ - struct IdentityToken *token; - char* audience; - char* issuer; - - issuer = GNUNET_STRINGS_data_to_string_alloc (iss, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - audience = GNUNET_STRINGS_data_to_string_alloc (aud, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - token = GNUNET_malloc (sizeof (struct IdentityToken)); - token_add_attr (token, "iss", issuer); - token_add_attr (token, "aud", audience); - token_add_attr (token, "sub", issuer); - token->aud_key = *aud; - GNUNET_free (issuer); - GNUNET_free (audience); - return token; -} - -void -token_destroy (struct IdentityToken *token) -{ - struct TokenAttr *attr; - struct TokenAttr *tmp_attr; - struct TokenAttrValue *val; - struct TokenAttrValue *tmp_val; - - for (attr = token->attr_head; NULL != attr;) - { - tmp_attr = attr->next; - GNUNET_CONTAINER_DLL_remove (token->attr_head, - token->attr_tail, - attr); - for (val = attr->val_head; NULL != val;) - { - tmp_val = val->next; - GNUNET_CONTAINER_DLL_remove (attr->val_head, - attr->val_tail, - val); - if (NULL != val->value) - GNUNET_free (val->value); - GNUNET_free (val); - val = tmp_val; - } - GNUNET_free (attr->name); - GNUNET_free (attr); - attr = tmp_attr; - } - - - GNUNET_free (token); -} - -void -token_add_attr (struct IdentityToken *token, - const char* key, - const char* value) -{ - struct TokenAttr *attr; - struct TokenAttrValue *new_val; - GNUNET_assert (NULL != token); - - new_val = GNUNET_malloc (sizeof (struct TokenAttrValue)); - new_val->value = GNUNET_strdup (value); - for (attr = token->attr_head; NULL != attr; attr = attr->next) - { - if (0 == strcmp (key, attr->name)) - break; - } - - if (NULL == attr) - { - attr = GNUNET_malloc (sizeof (struct TokenAttr)); - attr->name = GNUNET_strdup (key); - GNUNET_CONTAINER_DLL_insert (token->attr_head, - token->attr_tail, - attr); - } - - GNUNET_CONTAINER_DLL_insert (attr->val_head, - attr->val_tail, - new_val); -} - -void -token_add_attr_int (struct IdentityToken *token, - const char* key, - uint64_t value) -{ - struct TokenAttr *attr; - struct TokenAttrValue *new_val; - GNUNET_assert (NULL != token); - - new_val = GNUNET_malloc (sizeof (struct TokenAttrValue)); - new_val->int_value = value; - for (attr = token->attr_head; NULL != attr; attr = attr->next) - { - if (0 == strcmp (key, attr->name)) - break; - } - - if (NULL == attr) - { - attr = GNUNET_malloc (sizeof (struct TokenAttr)); - attr->name = GNUNET_strdup (key); - GNUNET_CONTAINER_DLL_insert (token->attr_head, - token->attr_tail, - attr); - } - - GNUNET_CONTAINER_DLL_insert (attr->val_head, - attr->val_tail, - new_val); -} - -static void -parse_json_payload(const char* payload_base64, - struct IdentityToken *token) -{ - const char *key; - const json_t *value; - const json_t *arr_value; - char *payload; - int idx; - json_t *payload_json; - json_error_t err_json; - - GNUNET_STRINGS_base64_decode (payload_base64, - strlen (payload_base64), - &payload); - //TODO signature and aud key - payload_json = json_loads (payload, JSON_DECODE_ANY, &err_json); - - json_object_foreach (payload_json, key, value) - { - if (json_is_array (value)) - { - json_array_foreach (value, idx, arr_value) - { - if (json_is_integer (arr_value)) - token_add_attr_int (token, key, - json_integer_value (arr_value)); - else - token_add_attr (token, - key, - json_string_value (arr_value)); - } - } else { - if (json_is_integer (value)) - token_add_attr_int (token, key, - json_integer_value (value)); - else - token_add_attr (token, key, json_string_value (value)); - } - } - - json_decref (payload_json); - GNUNET_free (payload); -} - -int -token_parse2 (const char* raw_data, - const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - struct IdentityToken **result) -{ - char *enc_token_str; - char *tmp_buf; - char *token_str; - char *enc_token; - char *payload_base64; - size_t enc_token_len; - - GNUNET_asprintf (&tmp_buf, "%s", raw_data); - strtok (tmp_buf, ","); - enc_token_str = strtok (NULL, ","); - - enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str, - strlen (enc_token_str), - &enc_token); - if (GNUNET_OK != decrypt_str_ecdhe2 (priv_key, - aud_key, - enc_token, - enc_token_len, - &token_str)) - { - GNUNET_free (tmp_buf); - GNUNET_free (enc_token); - return GNUNET_SYSERR; - } - - GNUNET_assert (NULL != strtok (token_str, ".")); - payload_base64 = strtok (NULL, "."); - - *result = GNUNET_malloc (sizeof (struct IdentityToken)); - parse_json_payload (payload_base64, *result); - - (*result)->aud_key = *aud_key; - GNUNET_free (enc_token); - GNUNET_free (token_str); - GNUNET_free (tmp_buf); - return GNUNET_OK; -} - -int -token_parse (const char* raw_data, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - struct IdentityToken **result) -{ - char *ecdh_pubkey_str; - char *enc_token_str; - char *tmp_buf; - char *token_str; - char *enc_token; - char *payload_base64; - size_t enc_token_len; - struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; - - GNUNET_asprintf (&tmp_buf, "%s", raw_data); - ecdh_pubkey_str = strtok (tmp_buf, ","); - enc_token_str = strtok (NULL, ","); - - GNUNET_assert (NULL != ecdh_pubkey_str); - GNUNET_assert (NULL != enc_token_str); - - GNUNET_STRINGS_string_to_data (ecdh_pubkey_str, - strlen (ecdh_pubkey_str), - &ecdh_pubkey, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - enc_token_len = GNUNET_STRINGS_base64_decode (enc_token_str, - strlen (enc_token_str), - &enc_token); - if (GNUNET_OK != decrypt_str_ecdhe (priv_key, - &ecdh_pubkey, - enc_token, - enc_token_len, - &token_str)) - { - GNUNET_free (tmp_buf); - GNUNET_free (enc_token); - return GNUNET_SYSERR; - } - - GNUNET_assert (NULL != strtok (token_str, ".")); - payload_base64 = strtok (NULL, "."); - - *result = GNUNET_malloc (sizeof (struct IdentityToken)); - parse_json_payload (payload_base64, *result); - - GNUNET_free (enc_token); - GNUNET_free (token_str); - GNUNET_free (tmp_buf); - return GNUNET_OK; -} - -static char* -create_json_payload (const struct IdentityToken *token) -{ - struct TokenAttr *attr; - struct TokenAttrValue *val; - json_t *root; - char *json_str; - - root = json_object(); - for (attr = token->attr_head; NULL != attr; attr = attr->next) - { - for (val = attr->val_head; NULL != val; val = val->next) - { - if (NULL != val->value) - { - json_object_set_new (root, - attr->name, - json_string (val->value)); - } else { - json_object_set_new (root, - attr->name, - json_integer (val->int_value)); - } - } - } - json_str = json_dumps (root, JSON_INDENT(1)); - json_decref (root); - return json_str; -} - -static char* -create_json_header(void) -{ - json_t *root; - char *json_str; - - root = json_object (); - json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); - json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); - - json_str = json_dumps (root, JSON_INDENT(1)); - json_decref (root); - return json_str; -} - -int -token_to_string (const struct IdentityToken *token, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - char **result) -{ - char *payload_str; - char *header_str; - char *payload_base64; - char *header_base64; - char *padding; - char *signature_target; - char *signature_str; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - header_str = create_json_header(); - GNUNET_STRINGS_base64_encode (header_str, - strlen (header_str), - &header_base64); - //Remove GNUNET padding of base64 - padding = strtok(header_base64, "="); - while (NULL != padding) - padding = strtok(NULL, "="); - - payload_str = create_json_payload (token); - GNUNET_STRINGS_base64_encode (payload_str, - strlen (payload_str), - &payload_base64); - - //Remove GNUNET padding of base64 - padding = strtok(payload_base64, "="); - while (NULL != padding) - padding = strtok(NULL, "="); - - GNUNET_asprintf (&signature_target, "%s,%s", header_base64, payload_base64); - purpose = - GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - strlen (signature_target)); - purpose->size = - htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); - purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN); - GNUNET_memcpy (&purpose[1], signature_target, strlen (signature_target)); - if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key, - purpose, - (struct GNUNET_CRYPTO_EcdsaSignature *)&token->signature)) - { - GNUNET_free (signature_target); - GNUNET_free (payload_str); - GNUNET_free (payload_base64); - GNUNET_free (header_base64); - GNUNET_free (purpose); - return GNUNET_SYSERR; - } - - GNUNET_STRINGS_base64_encode ((const char*)&token->signature, - sizeof (struct GNUNET_CRYPTO_EcdsaSignature), - &signature_str); - GNUNET_asprintf (result, "%s.%s.%s", - header_base64, payload_base64, signature_str); - GNUNET_free (signature_target); - GNUNET_free (payload_str); - GNUNET_free (header_str); - GNUNET_free (signature_str); - GNUNET_free (payload_base64); - GNUNET_free (header_base64); - GNUNET_free (purpose); - return GNUNET_OK; -} - -int -token_serialize (const struct IdentityToken *token, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey, - char **result) -{ - char *token_str; - char *enc_token; - char *dh_key_str; - char *enc_token_base64; - struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; - - GNUNET_assert (GNUNET_OK == token_to_string (token, - priv_key, - &token_str)); - - GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (token_str, - &token->aud_key, - &enc_token, - ecdh_privkey, - &ecdh_pubkey)); - GNUNET_STRINGS_base64_encode (enc_token, - strlen (token_str), - &enc_token_base64); - dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ecdh_pubkey, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - GNUNET_asprintf (result, "%s,%s", dh_key_str, enc_token_base64); - GNUNET_free (dh_key_str); - GNUNET_free (enc_token_base64); - GNUNET_free (enc_token); - GNUNET_free (token_str); - return GNUNET_OK; -} - -struct TokenTicketPayload* -ticket_payload_create (uint64_t nonce, - const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey, - const char* lbl_str) -{ - struct TokenTicketPayload* payload; - - payload = GNUNET_malloc (sizeof (struct TokenTicketPayload)); - payload->nonce = nonce; - payload->identity_key = *identity_pkey; - GNUNET_asprintf (&payload->label, lbl_str, strlen (lbl_str)); - return payload; -} - -void -ticket_payload_destroy (struct TokenTicketPayload* payload) -{ - if (NULL != payload->label) - GNUNET_free (payload->label); - GNUNET_free (payload); -} - -void -ticket_payload_serialize (struct TokenTicketPayload *payload, - char **result) -{ - char* identity_key_str; - - identity_key_str = GNUNET_STRINGS_data_to_string_alloc (&payload->identity_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - GNUNET_asprintf (result, - "{\"nonce\": \"%"SCNu64"\",\"identity\": \"%s\",\"label\": \"%s\"}", - payload->nonce, identity_key_str, payload->label); - GNUNET_free (identity_key_str); - -} - - -/** - * Create the token code - * The data is encrypted with a share ECDH derived secret using B (aud_key) - * and e (ecdh_privkey) - * The ticket also contains E (ecdh_pubkey) and a signature over the - * data and E - */ -struct TokenTicket* -ticket_create (uint64_t nonce, - const struct GNUNET_CRYPTO_EcdsaPublicKey* identity_pkey, - const char* lbl_str, - const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key) -{ - struct TokenTicket *ticket; - struct TokenTicketPayload *code_payload; - - ticket = GNUNET_malloc (sizeof (struct TokenTicket)); - code_payload = ticket_payload_create (nonce, - identity_pkey, - lbl_str); - ticket->aud_key = *aud_key; - ticket->payload = code_payload; - - - return ticket; -} - -void -ticket_destroy (struct TokenTicket *ticket) -{ - ticket_payload_destroy (ticket->payload); - GNUNET_free (ticket); -} - -int -ticket_serialize (struct TokenTicket *ticket, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - char **result) -{ - char *code_payload_str; - char *enc_ticket_payload; - char *ticket_payload_str; - char *ticket_sig_str; - char *ticket_str; - char *dh_key_str; - char *write_ptr; - struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey; - - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - - ticket_payload_serialize (ticket->payload, - &code_payload_str); - - GNUNET_assert (GNUNET_OK == encrypt_str_ecdhe (code_payload_str, - &ticket->aud_key, - &enc_ticket_payload, - &ecdhe_privkey, - &ticket->ecdh_pubkey)); - - GNUNET_free (ecdhe_privkey); - - purpose = - GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E - strlen (code_payload_str)); // E_K (code_str) - purpose->size = - htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + - strlen (code_payload_str)); - purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET); - write_ptr = (char*) &purpose[1]; - GNUNET_memcpy (write_ptr, - &ticket->ecdh_pubkey, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey); - GNUNET_memcpy (write_ptr, enc_ticket_payload, strlen (code_payload_str)); - GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (priv_key, - purpose, - &ticket->signature)); - GNUNET_STRINGS_base64_encode (enc_ticket_payload, - strlen (code_payload_str), - &ticket_payload_str); - ticket_sig_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->signature, - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); - - dh_key_str = GNUNET_STRINGS_data_to_string_alloc (&ticket->ecdh_pubkey, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using ECDH pubkey %s to encrypt\n", dh_key_str); - GNUNET_asprintf (&ticket_str, "{\"data\": \"%s\", \"ecdh\": \"%s\", \"signature\": \"%s\"}", - ticket_payload_str, dh_key_str, ticket_sig_str); - GNUNET_STRINGS_base64_encode (ticket_str, strlen (ticket_str), result); - GNUNET_free (dh_key_str); - GNUNET_free (purpose); - GNUNET_free (ticket_str); - GNUNET_free (ticket_sig_str); - GNUNET_free (code_payload_str); - GNUNET_free (enc_ticket_payload); - GNUNET_free (ticket_payload_str); - return GNUNET_OK; -} - -int -ticket_payload_parse(const char *raw_data, - ssize_t data_len, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - const struct GNUNET_CRYPTO_EcdhePublicKey *ecdhe_pkey, - struct TokenTicketPayload **result) -{ - const char* label_str; - const char* nonce_str; - const char* identity_key_str; - - json_t *root; - json_t *label_json; - json_t *identity_json; - json_t *nonce_json; - json_error_t err_json; - char* data_str; - uint64_t nonce; - struct GNUNET_CRYPTO_EcdsaPublicKey id_pkey; - - if (GNUNET_OK != decrypt_str_ecdhe (priv_key, - ecdhe_pkey, - raw_data, - data_len, - &data_str)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Data decryption failed\n"); - return GNUNET_SYSERR; - } - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Data: %s\n", data_str); - root = json_loads (data_str, JSON_DECODE_ANY, &err_json); - if (!root) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing data: %s\n", err_json.text); - GNUNET_free (data_str); - return GNUNET_SYSERR; - } - - identity_json = json_object_get (root, "identity"); - if (!json_is_string (identity_json)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing data: %s\n", err_json.text); - json_decref (root); - GNUNET_free (data_str); - return GNUNET_SYSERR; - } - identity_key_str = json_string_value (identity_json); - GNUNET_STRINGS_string_to_data (identity_key_str, - strlen (identity_key_str), - &id_pkey, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - - - label_json = json_object_get (root, "label"); - if (!json_is_string (label_json)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing data: %s\n", err_json.text); - json_decref (root); - GNUNET_free (data_str); - return GNUNET_SYSERR; - } - - label_str = json_string_value (label_json); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found label: %s\n", label_str); - - nonce_json = json_object_get (root, "nonce"); - if (!json_is_string (label_json)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error parsing data: %s\n", err_json.text); - json_decref (root); - GNUNET_free (data_str); - return GNUNET_SYSERR; - } - - nonce_str = json_string_value (nonce_json); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found nonce: %s\n", nonce_str); - - GNUNET_assert (0 != sscanf (nonce_str, "%"SCNu64, &nonce)); - - *result = ticket_payload_create (nonce, - (const struct GNUNET_CRYPTO_EcdsaPublicKey*)&id_pkey, - label_str); - GNUNET_free (data_str); - json_decref (root); - return GNUNET_OK; - -} - -int -ticket_parse (const char *raw_data, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - struct TokenTicket **result) -{ - const char* enc_data_str; - const char* ecdh_enc_str; - const char* signature_enc_str; - - json_t *root; - json_t *signature_json; - json_t *ecdh_json; - json_t *enc_data_json; - json_error_t err_json; - char* enc_data; - char* ticket_decoded; - char* write_ptr; - size_t enc_data_len; - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; - struct TokenTicket *ticket; - struct TokenTicketPayload *ticket_payload; - - ticket_decoded = NULL; - GNUNET_STRINGS_base64_decode (raw_data, strlen (raw_data), &ticket_decoded); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ticket: %s\n", ticket_decoded); - root = json_loads (ticket_decoded, JSON_DECODE_ANY, &err_json); - if (!root) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "%s\n", err_json.text); - return GNUNET_SYSERR; - } - - signature_json = json_object_get (root, "signature"); - ecdh_json = json_object_get (root, "ecdh"); - enc_data_json = json_object_get (root, "data"); - - signature_enc_str = json_string_value (signature_json); - ecdh_enc_str = json_string_value (ecdh_json); - enc_data_str = json_string_value (enc_data_json); - - ticket = GNUNET_malloc (sizeof (struct TokenTicket)); - - if (GNUNET_OK != GNUNET_STRINGS_string_to_data (ecdh_enc_str, - strlen (ecdh_enc_str), - &ticket->ecdh_pubkey, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH PKEY %s invalid in data\n", ecdh_enc_str); - json_decref (root); - GNUNET_free (ticket); - return GNUNET_SYSERR; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using ECDH pubkey %s for data decryption\n", ecdh_enc_str); - if (GNUNET_OK != GNUNET_STRINGS_string_to_data (signature_enc_str, - strlen (signature_enc_str), - &ticket->signature, - sizeof (struct GNUNET_CRYPTO_EcdsaSignature))) - { - json_decref (root); - GNUNET_free (ticket_decoded); - GNUNET_free (ticket); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ECDH signature invalid in data\n"); - return GNUNET_SYSERR; - } - - enc_data_len = GNUNET_STRINGS_base64_decode (enc_data_str, - strlen (enc_data_str), - &enc_data); - - - if (GNUNET_OK != ticket_payload_parse (enc_data, - enc_data_len, - priv_key, - (const struct GNUNET_CRYPTO_EcdhePublicKey*)&ticket->ecdh_pubkey, - &ticket_payload)) - { - json_decref (root); - GNUNET_free (enc_data); - GNUNET_free (ticket_decoded); - GNUNET_free (ticket); - return GNUNET_SYSERR; - } - - ticket->payload = ticket_payload; - purpose = - GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + //E - enc_data_len); // E_K (code_str) - purpose->size = - htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + - enc_data_len); - purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET); - write_ptr = (char*) &purpose[1]; - GNUNET_memcpy (write_ptr, &ticket->ecdh_pubkey, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePublicKey); - GNUNET_memcpy (write_ptr, enc_data, enc_data_len); - - if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNUID_TICKET, - purpose, - &ticket->signature, - &ticket_payload->identity_key)) - { - ticket_destroy (ticket); - GNUNET_free (ticket_decoded); - json_decref (root); - GNUNET_free (purpose); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Error verifying signature for ticket\n"); - return GNUNET_SYSERR; - } - *result = ticket; - GNUNET_free (purpose); - - GNUNET_free (enc_data); - GNUNET_free (ticket_decoded); - json_decref (root); - return GNUNET_OK; - -} - - - -/* end of identity_token.c */ diff --git a/src/identity-provider/identity_token.h b/src/identity-provider/identity_token.h deleted file mode 100644 index 7ded6662e..000000000 --- a/src/identity-provider/identity_token.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012-2015 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. - */ -/** - * @author Martin Schanzenbach - * @file identity-provider/identity_token.h - * @brief GNUnet Identity Provider library - * - */ -#ifndef IDENTITY_TOKEN_H -#define IDENTITY_TOKEN_H - -#include "gnunet_crypto_lib.h" -#include <jansson.h> - -struct IdentityToken -{ - /** - * DLL - */ - struct TokenAttr *attr_head; - - /** - * DLL - */ - struct TokenAttr *attr_tail; - - /** - * Token Signature - */ - struct GNUNET_CRYPTO_EcdsaSignature signature; - - /** - * Audience Pubkey - */ - struct GNUNET_CRYPTO_EcdsaPublicKey aud_key; -}; - -struct TokenAttr -{ - /** - * DLL - */ - struct TokenAttr *next; - - /** - * DLL - */ - struct TokenAttr *prev; - - /** - * Attribute name - */ - char *name; - - /** - * Attribute value DLL - */ - struct TokenAttrValue *val_head; - - /** - * Attribute value DLL - */ - struct TokenAttrValue *val_tail; - -}; - -struct TokenAttrValue -{ - /** - * DLL - */ - struct TokenAttrValue *next; - - /** - * DLL - */ - struct TokenAttrValue *prev; - - /** - * Attribute value - */ - char *value; - - /** - * Attribute int value - * used if NULL == value - */ - uint64_t int_value; -}; - -struct TokenTicketPayload -{ - /** - * Nonce - */ - uint64_t nonce; - - /** - * Label - */ - char *label; - - /** - * Issuing Identity - */ - struct GNUNET_CRYPTO_EcdsaPublicKey identity_key; -}; - - -struct TokenTicket -{ - /** - * Meta info - */ - struct TokenTicketPayload *payload; - - /** - * ECDH Pubkey - */ - struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; - - /** - * Signature - */ - struct GNUNET_CRYPTO_EcdsaSignature signature; - - /** - * Target identity - */ - struct GNUNET_CRYPTO_EcdsaPublicKey aud_key; -}; - - - -/** - * Create an identity token - * - * @param iss the issuer string for the token - * @param aud the audience of the token - * - * @return a new token - */ -struct IdentityToken* -token_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *iss, - const struct GNUNET_CRYPTO_EcdsaPublicKey* aud); - -/** - * Destroy an identity token - * - * @param token the token to destroy - */ -void -token_destroy (struct IdentityToken*token); - -/** - * Add a new key value pair to the token - * - * @param token the token to modify - * @param key the key - * @param value the value - */ -void -token_add_attr (struct IdentityToken *token, - const char* key, - const char* value); - -/** - * Add a new key value pair to the token - * - * @param token the token to modify - * @param key the key - * @param value the value - */ -void -token_add_attr_int (struct IdentityToken *token, - const char* key, - uint64_t value); - - - -/** - * Add a value to a TokenAttribute - * - * @param attr the token attribute - * @param value value to add - */ - void - token_attr_add_value (const struct TokenAttr *attr, - const char *value); - -/** - * Add a new key value pair to the token with the value as json - * - * @param the token to modify - * @param key the key - * @param value the value - * - */ - void - token_add_json (const struct IdentityToken *token, - const char* key, - json_t* value); - -/** - * Serialize a token. The token will be signed and base64 according to the - * JWT format. The signature is base32-encoded ECDSA. - * The resulting JWT is encrypted using - * ECDHE for the audience and Base64 - * encoded in result. The audience requires the ECDHE public key P - * to decrypt the token T. The key P is included in the result and prepended - * before the token - * - * @param token the token to serialize - * @param priv_key the private key used to sign the token - * @param ecdhe_privkey the ECDHE private key used to encrypt the token - * @param result P,Base64(E(T)) - * - * @return GNUNET_OK on success - */ - int - token_serialize (const struct IdentityToken*token, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - struct GNUNET_CRYPTO_EcdhePrivateKey **ecdhe_privkey, - char **result); - -/** - * Parses the serialized token and returns a token - * - * @param data the serialized token - * @param priv_key the private key of the audience - * @param result the token - * - * @return GNUNET_OK on success - */ - int - token_parse (const char* data, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - struct IdentityToken **result); - -/** - * Parses the serialized token and returns a token - * This variant is intended for the party that issued the token and also - * wants to decrypt the serialized token. - * - * @param data the serialized token - * @param priv_key the private (!) ECDHE key - * @param aud_key the identity of the audience - * @param result the token - * - * @return GNUNET_OK on success - */ -int -token_parse2 (const char* data, - const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_key, - const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key, - struct IdentityToken **result); - - -/** - * - * Returns a JWT-string representation of the token - * - * @param token the token - * @param priv_key the private key used to sign the JWT - * @param result the JWT - * - * @return GNUNET_OK on success - */ - int - token_to_string (const struct IdentityToken *token, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - char **result); - -/** - * - * Creates a ticket that can be exchanged by the audience for - * the token. The token must be placed under the label - * - * @param nonce nonce provided by the audience that requested the ticket - * @param iss_pkey the issuer pubkey used to sign the ticket - * @param label the label encoded in the ticket - * @param aud_ley the audience pubkey used to encrypt the ticket payload - * - * @return the ticket - */ -struct TokenTicket* -ticket_create (uint64_t nonce, - const struct GNUNET_CRYPTO_EcdsaPublicKey* iss_pkey, - const char* lbl_str, - const struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key); - -/** - * Serialize a ticket. Returns the Base64 representation of the ticket. - * Format: Base64( { payload: E(Payload), ecdhe: K, signature: signature } ) - * - * @param ticket the ticket to serialize - * @param priv_key the issuer private key to sign the ticket payload - * @param result the serialized ticket - * - * @return GNUNET_OK on success - */ - int - ticket_serialize (struct TokenTicket *ticket, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - char **result); - -/** - * Destroys a ticket - * - * @param the ticket to destroy - */ -void -ticket_destroy (struct TokenTicket *ticket); - -/** - * Parses a serialized ticket - * - * @param data the serialized ticket - * @param priv_key the audience private key - * @param ticket the ticket - * - * @return GNUNET_OK on success - */ -int -ticket_parse (const char* raw_data, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key, - struct TokenTicket **ticket); - -#endif diff --git a/src/identity-provider/jwt.c b/src/identity-provider/jwt.c new file mode 100644 index 000000000..2f1e3240b --- /dev/null +++ b/src/identity-provider/jwt.c @@ -0,0 +1,180 @@ +/* + This file is part of GNUnet + Copyright (C) 2010-2015 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + */ + +/** + * @file identity-provider/jwt.c + * @brief helper library for JSON-Web-Tokens + * @author Martin Schanzenbach + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_signatures.h" +#include "gnunet_identity_attribute_lib.h" +#include <jansson.h> + + +#define JWT_ALG "alg" + +/*TODO is this the correct way to define new algs? */ +#define JWT_ALG_VALUE "ED512" + +#define JWT_TYP "typ" + +#define JWT_TYP_VALUE "jwt" + +static char* +create_jwt_header(void) +{ + json_t *root; + char *json_str; + + root = json_object (); + json_object_set_new (root, JWT_ALG, json_string (JWT_ALG_VALUE)); + json_object_set_new (root, JWT_TYP, json_string (JWT_TYP_VALUE)); + + json_str = json_dumps (root, JSON_INDENT(1)); + json_decref (root); + return json_str; +} + +/** + * Create a JWT from attributes + * + * @param sub_key the public of the subject + * @param attrs the attribute list + * @param priv_key the key used to sign the JWT + * @return a new base64-encoded JWT string. + */ +char* +jwt_create_from_list (const struct GNUNET_CRYPTO_EcdsaPublicKey *sub_key, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key) +{ + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimListEntry *le; + struct GNUNET_CRYPTO_EcdsaPublicKey iss_key; + struct GNUNET_CRYPTO_EcdsaSignature signature; + struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; + char* audience; + char* issuer; + char* header; + char* padding; + char* body_str; + char* result; + char* header_base64; + char* body_base64; + char* signature_target; + char* signature_base64; + char* attr_val_str; + json_t* body; + + GNUNET_CRYPTO_ecdsa_key_get_public (priv_key, &iss_key); + /* TODO maybe we should use a local identity here */ + issuer = GNUNET_STRINGS_data_to_string_alloc (&iss_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + audience = GNUNET_STRINGS_data_to_string_alloc (sub_key, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + header = create_jwt_header (); + body = json_object (); + /* TODO who is the issuer? local IdP or subject ? See self-issued tokens? */ + json_object_set_new (body, + "iss", json_string (issuer)); + json_object_set_new (body, + "sub", json_string (issuer)); + /* TODO what should be in here exactly? */ + json_object_set_new (body, + "aud", json_string (audience)); + for (le = attrs->list_head; NULL != le; le = le->next) + { + /** + * TODO here we should have a function that + * calls the Attribute plugins to create a + * json representation for its value + */ + attr_val_str = GNUNET_IDENTITY_ATTRIBUTE_value_to_string (le->claim->type, + le->claim->data, + le->claim->data_size); + json_object_set_new (body, + le->claim->name, + json_string (attr_val_str)); + GNUNET_free (attr_val_str); + } + body_str = json_dumps (body, JSON_INDENT(0)); + json_decref (body); + + GNUNET_STRINGS_base64_encode (header, + strlen (header), + &header_base64); + //Remove GNUNET padding of base64 + padding = strtok(header_base64, "="); + while (NULL != padding) + padding = strtok(NULL, "="); + + GNUNET_STRINGS_base64_encode (body_str, + strlen (body_str), + &body_base64); + + //Remove GNUNET padding of base64 + padding = strtok(body_base64, "="); + while (NULL != padding) + padding = strtok(NULL, "="); + + GNUNET_free (issuer); + GNUNET_free (audience); + + /** + * TODO + * Creating the JWT signature. This might not be + * standards compliant, check. + */ + GNUNET_asprintf (&signature_target, "%s,%s", header_base64, body_base64); + + purpose = + GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + + strlen (signature_target)); + purpose->size = + htonl (strlen (signature_target) + sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); + purpose->purpose = htonl(GNUNET_SIGNATURE_PURPOSE_GNUID_TOKEN); + GNUNET_memcpy (&purpose[1], signature_target, strlen (signature_target)); + if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (priv_key, + purpose, + (struct GNUNET_CRYPTO_EcdsaSignature *)&signature)) + { + GNUNET_free (signature_target); + GNUNET_free (body_str); + GNUNET_free (body_base64); + GNUNET_free (header_base64); + GNUNET_free (purpose); + return NULL; + } + GNUNET_STRINGS_base64_encode ((const char*)&signature, + sizeof (struct GNUNET_CRYPTO_EcdsaSignature), + &signature_base64); + GNUNET_asprintf (&result, "%s.%s.%s", + header_base64, body_base64, signature_base64); + + GNUNET_free (signature_target); + GNUNET_free (header); + GNUNET_free (body_str); + GNUNET_free (signature_base64); + GNUNET_free (body_base64); + GNUNET_free (header_base64); + GNUNET_free (purpose); + return result; +} diff --git a/src/identity/plugin_gnsrecord_identity.c b/src/identity-provider/plugin_gnsrecord_identity_provider.c index c26c04074..6ed0b0852 100644 --- a/src/identity/plugin_gnsrecord_identity.c +++ b/src/identity-provider/plugin_gnsrecord_identity_provider.c @@ -19,9 +19,9 @@ */ /** - * @file identity/plugin_gnsrecord_identity.c + * @file identity-provider/plugin_gnsrecord_identity_provider.c * @brief gnsrecord plugin to provide the API for identity records - * @author Christian Grothoff + * @author Martin Schanzenbach */ #include "platform.h" #include "gnunet_util_lib.h" @@ -54,9 +54,13 @@ value_to_string (void *cls, switch (type) { case GNUNET_GNSRECORD_TYPE_ID_ATTR: - case GNUNET_GNSRECORD_TYPE_ID_TOKEN: + return GNUNET_STRINGS_data_to_string_alloc (data, data_size); + case GNUNET_GNSRECORD_TYPE_ID_TOKEN: //DEPRECATED return GNUNET_strndup (data, data_size); - case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: + case GNUNET_GNSRECORD_TYPE_ABE_KEY: + case GNUNET_GNSRECORD_TYPE_ABE_MASTER: + return GNUNET_STRINGS_data_to_string_alloc (data, data_size); + case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: //DEPRECATED ecdhe_privkey = data; audience_pubkey = data+sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey); scopes = (char*) audience_pubkey+(sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); @@ -106,12 +110,22 @@ string_to_value (void *cls, switch (type) { case GNUNET_GNSRECORD_TYPE_ID_ATTR: + return GNUNET_STRINGS_string_to_data (s, + strlen (s), + *data, + *data_size); case GNUNET_GNSRECORD_TYPE_ID_TOKEN: *data = GNUNET_strdup (s); *data_size = strlen (s); return GNUNET_OK; + case GNUNET_GNSRECORD_TYPE_ABE_KEY: + case GNUNET_GNSRECORD_TYPE_ABE_MASTER: + return GNUNET_STRINGS_string_to_data (s, + strlen (s), + *data, + *data_size); case GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA: - tmp_tok = GNUNET_strdup (s); + tmp_tok = GNUNET_strdup (s); ecdhe_str = strtok (tmp_tok, ";"); if (NULL == ecdhe_str) { @@ -160,15 +174,17 @@ string_to_value (void *cls, * Mapping of record type numbers to human-readable * record type names. */ - static struct { - const char *name; - uint32_t number; - } name_map[] = { - { "ID_ATTR", GNUNET_GNSRECORD_TYPE_ID_ATTR }, - { "ID_TOKEN", GNUNET_GNSRECORD_TYPE_ID_TOKEN }, - { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA }, - { NULL, UINT32_MAX } - }; +static struct { + const char *name; + uint32_t number; +} name_map[] = { + { "ID_ATTR", GNUNET_GNSRECORD_TYPE_ID_ATTR }, + { "ID_TOKEN", GNUNET_GNSRECORD_TYPE_ID_TOKEN }, + { "ABE_KEY", GNUNET_GNSRECORD_TYPE_ABE_KEY }, + { "ABE_MASTER", GNUNET_GNSRECORD_TYPE_ABE_MASTER }, + { "ID_TOKEN_METADATA", GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA }, + { NULL, UINT32_MAX } +}; /** @@ -220,7 +236,7 @@ number_to_typename (void *cls, * @return the exported block API */ void * -libgnunet_plugin_gnsrecord_identity_init (void *cls) +libgnunet_plugin_gnsrecord_identity_provider_init (void *cls) { struct GNUNET_GNSRECORD_PluginFunctions *api; @@ -240,7 +256,7 @@ libgnunet_plugin_gnsrecord_identity_init (void *cls) * @return NULL */ void * -libgnunet_plugin_gnsrecord_identity_done (void *cls) +libgnunet_plugin_gnsrecord_identity_provider_done (void *cls) { struct GNUNET_GNSRECORD_PluginFunctions *api = cls; diff --git a/src/identity-provider/plugin_identity_provider_sqlite.c b/src/identity-provider/plugin_identity_provider_sqlite.c new file mode 100644 index 000000000..0071528b9 --- /dev/null +++ b/src/identity-provider/plugin_identity_provider_sqlite.c @@ -0,0 +1,736 @@ + /* + * This file is part of GNUnet + * Copyright (C) 2009-2017 GNUnet e.V. + * + * GNUnet is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 3, or (at your + * option) any later version. + * + * GNUnet is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNUnet; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * @file identity-provider/plugin_identity_provider_sqlite.c + * @brief sqlite-based idp backend + * @author Martin Schanzenbach + */ + +#include "platform.h" +#include "gnunet_identity_provider_service.h" +#include "gnunet_identity_provider_plugin.h" +#include "gnunet_identity_attribute_lib.h" +#include "gnunet_sq_lib.h" +#include <sqlite3.h> + +/** + * After how many ms "busy" should a DB operation fail for good? A + * low value makes sure that we are more responsive to requests + * (especially PUTs). A high value guarantees a higher success rate + * (SELECTs in iterate can take several seconds despite LIMIT=1). + * + * The default value of 1s should ensure that users do not experience + * huge latencies while at the same time allowing operations to + * succeed with reasonable probability. + */ +#define BUSY_TIMEOUT_MS 1000 + + +/** + * Log an error message at log-level 'level' that indicates + * a failure of the command 'cmd' on file 'filename' + * with the message given by strerror(errno). + */ +#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "identity-provider", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0) + +#define LOG(kind,...) GNUNET_log_from (kind, "identity-provider-sqlite", __VA_ARGS__) + + +/** + * Context for all functions in this plugin. + */ +struct Plugin +{ + + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Database filename. + */ + char *fn; + + /** + * Native SQLite database handle. + */ + sqlite3 *dbh; + + /** + * Precompiled SQL to store ticket. + */ + sqlite3_stmt *store_ticket; + + /** + * Precompiled SQL to delete existing ticket. + */ + sqlite3_stmt *delete_ticket; + + /** + * Precompiled SQL to iterate tickets. + */ + sqlite3_stmt *iterate_tickets; + + /** + * Precompiled SQL to get ticket attributes. + */ + sqlite3_stmt *get_ticket_attrs; + + /** + * Precompiled SQL to iterate tickets by audience. + */ + sqlite3_stmt *iterate_tickets_by_audience; +}; + + +/** + * @brief Prepare a SQL statement + * + * @param dbh handle to the database + * @param zSql SQL statement, UTF-8 encoded + * @param ppStmt set to the prepared statement + * @return 0 on success + */ +static int +sq_prepare (sqlite3 *dbh, + const char *zSql, + sqlite3_stmt **ppStmt) +{ + char *dummy; + int result; + + result = + sqlite3_prepare_v2 (dbh, + zSql, + strlen (zSql), + ppStmt, + (const char **) &dummy); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Prepared `%s' / %p: %d\n", + zSql, + *ppStmt, + result); + return result; +} + +/** + * Create our database indices. + * + * @param dbh handle to the database + */ +static void +create_indices (sqlite3 * dbh) +{ + /* create indices */ + if ( (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS identity_reverse ON identity001tickets (identity,audience)", + NULL, NULL, NULL)) || + (SQLITE_OK != + sqlite3_exec (dbh, + "CREATE INDEX IF NOT EXISTS it_iter ON identity001tickets (rnd)", + NULL, NULL, NULL)) ) + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to create indices: %s\n", + sqlite3_errmsg (dbh)); +} + + + +#if 0 +#define CHECK(a) GNUNET_break(a) +#define ENULL NULL +#else +#define ENULL &e +#define ENULL_DEFINED 1 +#define CHECK(a) if (! (a)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); } +#endif + + +/** + * Initialize the database connections and associated + * data structures (create tables and indices + * as needed as well). + * + * @param plugin the plugin context (state for this module) + * @return #GNUNET_OK on success + */ +static int +database_setup (struct Plugin *plugin) +{ + sqlite3_stmt *stmt; + char *afsdir; +#if ENULL_DEFINED + char *e; +#endif + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, + "identity-provider-sqlite", + "FILENAME", + &afsdir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "identity-provider-sqlite", + "FILENAME"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_DISK_file_test (afsdir)) + { + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (afsdir)) + { + GNUNET_break (0); + GNUNET_free (afsdir); + return GNUNET_SYSERR; + } + } + /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ + plugin->fn = afsdir; + + /* Open database and precompile statements */ + if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + _("Unable to initialize SQLite: %s.\n"), + sqlite3_errmsg (plugin->dbh)); + return GNUNET_SYSERR; + } + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA temp_store=MEMORY", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA synchronous=NORMAL", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA legacy_file_format=OFF", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA auto_vacuum=INCREMENTAL", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA encoding=\"UTF-8\"", NULL, + NULL, ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, + ENULL)); + CHECK (SQLITE_OK == + sqlite3_exec (plugin->dbh, + "PRAGMA page_size=4092", NULL, NULL, + ENULL)); + + CHECK (SQLITE_OK == + sqlite3_busy_timeout (plugin->dbh, + BUSY_TIMEOUT_MS)); + + + /* Create table */ + CHECK (SQLITE_OK == + sq_prepare (plugin->dbh, + "SELECT 1 FROM sqlite_master WHERE tbl_name = 'identity001tickets'", + &stmt)); + if ((sqlite3_step (stmt) == SQLITE_DONE) && + (sqlite3_exec + (plugin->dbh, + "CREATE TABLE identity001tickets (" + " identity BLOB NOT NULL DEFAULT ''," + " audience BLOB NOT NULL DEFAULT ''," + " rnd INT8 NOT NULL DEFAULT ''," + " attributes BLOB NOT NULL DEFAULT ''" + ")", + NULL, NULL, NULL) != SQLITE_OK)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, + "sqlite3_exec"); + sqlite3_finalize (stmt); + return GNUNET_SYSERR; + } + sqlite3_finalize (stmt); + + create_indices (plugin->dbh); + + if ( (SQLITE_OK != + sq_prepare (plugin->dbh, + "INSERT INTO identity001tickets (identity, audience, rnd, attributes)" + " VALUES (?, ?, ?, ?)", + &plugin->store_ticket)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "DELETE FROM identity001tickets WHERE identity=? AND rnd=?", + &plugin->delete_ticket)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "SELECT identity,audience,rnd,attributes" + " FROM identity001tickets WHERE identity=? AND rnd=?", + &plugin->get_ticket_attrs)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "SELECT identity,audience,rnd,attributes" + " FROM identity001tickets WHERE identity=?" + " ORDER BY rnd LIMIT 1 OFFSET ?", + &plugin->iterate_tickets)) || + (SQLITE_OK != + sq_prepare (plugin->dbh, + "SELECT identity,audience,rnd,attributes" + " FROM identity001tickets WHERE audience=?" + " ORDER BY rnd LIMIT 1 OFFSET ?", + &plugin->iterate_tickets_by_audience)) ) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR, + "precompiling"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Shutdown database connection and associate data + * structures. + * @param plugin the plugin context (state for this module) + */ +static void +database_shutdown (struct Plugin *plugin) +{ + int result; + sqlite3_stmt *stmt; + + if (NULL != plugin->store_ticket) + sqlite3_finalize (plugin->store_ticket); + if (NULL != plugin->delete_ticket) + sqlite3_finalize (plugin->delete_ticket); + if (NULL != plugin->iterate_tickets) + sqlite3_finalize (plugin->iterate_tickets); + if (NULL != plugin->iterate_tickets_by_audience) + sqlite3_finalize (plugin->iterate_tickets_by_audience); + if (NULL != plugin->get_ticket_attrs) + sqlite3_finalize (plugin->get_ticket_attrs); + result = sqlite3_close (plugin->dbh); + if (result == SQLITE_BUSY) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + _("Tried to close sqlite without finalizing all prepared statements.\n")); + stmt = sqlite3_next_stmt (plugin->dbh, + NULL); + while (NULL != stmt) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Closing statement %p\n", + stmt); + result = sqlite3_finalize (stmt); + if (result != SQLITE_OK) + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "sqlite", + "Failed to close statement %p: %d\n", + stmt, + result); + stmt = sqlite3_next_stmt (plugin->dbh, + NULL); + } + result = sqlite3_close (plugin->dbh); + } + if (SQLITE_OK != result) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR, + "sqlite3_close"); + + GNUNET_free_non_null (plugin->fn); +} + + +/** + * Store a ticket in the database. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to persist + * @param attrs the attributes associated with the ticket + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +identity_provider_sqlite_store_ticket (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + const struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs) +{ + struct Plugin *plugin = cls; + size_t attrs_len; + char *attrs_ser; + int n; + + { + /* First delete duplicates */ + struct GNUNET_SQ_QueryParam dparams[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_end + }; + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->delete_ticket, + dparams)) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->delete_ticket); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->delete_ticket); + GNUNET_SQ_reset (plugin->dbh, + plugin->delete_ticket); + + attrs_len = GNUNET_IDENTITY_ATTRIBUTE_list_serialize_get_size (attrs); + attrs_ser = GNUNET_malloc (attrs_len); + GNUNET_IDENTITY_ATTRIBUTE_list_serialize (attrs, + attrs_ser); + struct GNUNET_SQ_QueryParam sparams[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_auto_from_type (&ticket->audience), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_fixed_size (attrs_ser, attrs_len), + GNUNET_SQ_query_param_end + }; + + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->store_ticket, + sparams)) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->store_ticket); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->store_ticket); + GNUNET_SQ_reset (plugin->dbh, + plugin->store_ticket); + GNUNET_free (attrs_ser); + } + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Ticket stored\n"); + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * Store a ticket in the database. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to delete + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +identity_provider_sqlite_delete_ticket (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) +{ + struct Plugin *plugin = cls; + int n; + + { + struct GNUNET_SQ_QueryParam sparams[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_end + }; + + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->delete_ticket, + sparams)) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->store_ticket); + return GNUNET_SYSERR; + } + n = sqlite3_step (plugin->delete_ticket); + GNUNET_SQ_reset (plugin->dbh, + plugin->delete_ticket); + } + switch (n) + { + case SQLITE_DONE: + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "sqlite", + "Ticket deleted\n"); + return GNUNET_OK; + case SQLITE_BUSY: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_NO; + default: + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_step"); + return GNUNET_SYSERR; + } +} + + +/** + * The given 'sqlite' statement has been prepared to be run. + * It will return a record which should be given to the iterator. + * Runs the statement and parses the returned record. + * + * @param plugin plugin context + * @param stmt to run (and then clean up) + * @param iter iterator to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error + */ +static int +get_ticket_and_call_iterator (struct Plugin *plugin, + sqlite3_stmt *stmt, + GNUNET_IDENTITY_PROVIDER_TicketIterator iter, + void *iter_cls) +{ + struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; + struct GNUNET_IDENTITY_ATTRIBUTE_ClaimList *attrs; + int ret; + int sret; + size_t attrs_len; + char *attrs_ser; + + ret = GNUNET_NO; + if (SQLITE_ROW == (sret = sqlite3_step (stmt))) + { + struct GNUNET_SQ_ResultSpec rs[] = { + GNUNET_SQ_result_spec_auto_from_type (&ticket.identity), + GNUNET_SQ_result_spec_auto_from_type (&ticket.audience), + GNUNET_SQ_result_spec_uint64 (&ticket.rnd), + GNUNET_SQ_result_spec_variable_size ((void**)&attrs_ser, + &attrs_len), + GNUNET_SQ_result_spec_end + + }; + ret = GNUNET_SQ_extract_result (stmt, + rs); + if (GNUNET_OK != ret) + { + GNUNET_break (0); + ret = GNUNET_SYSERR; + } + else + { + attrs = GNUNET_IDENTITY_ATTRIBUTE_list_deserialize (attrs_ser, + attrs_len); + if (NULL != iter) + iter (iter_cls, + &ticket, + attrs); + GNUNET_IDENTITY_ATTRIBUTE_list_destroy (attrs); + ret = GNUNET_YES; + } + GNUNET_SQ_cleanup_result (rs); + } + else + { + if (SQLITE_DONE != sret) + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR, + "sqlite_step"); + } + GNUNET_SQ_reset (plugin->dbh, + stmt); + return ret; +} + + +/** + * Lookup tickets in the datastore. + * + * @param cls closure (internal context for the plugin) + * @param ticket the ticket to retrieve attributes for + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, else #GNUNET_SYSERR + */ +static int +identity_provider_sqlite_ticket_get_attrs (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, + GNUNET_IDENTITY_PROVIDER_TicketIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + struct GNUNET_SQ_QueryParam params[] = { + GNUNET_SQ_query_param_auto_from_type (&ticket->identity), + GNUNET_SQ_query_param_uint64 (&ticket->rnd), + GNUNET_SQ_query_param_end + }; + + if (GNUNET_OK != + GNUNET_SQ_bind (plugin->get_ticket_attrs, + params)) + { + LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + plugin->get_ticket_attrs); + return GNUNET_SYSERR; + } + return get_ticket_and_call_iterator (plugin, + plugin->get_ticket_attrs, + iter, + iter_cls); +} + + +/** + * Iterate over the results for a particular key and zone in the + * datastore. Will return at most one result to the iterator. + * + * @param cls closure (internal context for the plugin) + * @param identity the issuing identity or audience (depending on audience switch) + * @param audience GNUNET_YES if identity is audience + * @param offset offset in the list of all matching records + * @param iter function to call with the result + * @param iter_cls closure for @a iter + * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error + */ +static int +identity_provider_sqlite_iterate_tickets (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + int audience, + uint64_t offset, + GNUNET_IDENTITY_PROVIDER_TicketIterator iter, + void *iter_cls) +{ + struct Plugin *plugin = cls; + sqlite3_stmt *stmt; + int err; + + if (NULL == identity) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + struct GNUNET_SQ_QueryParam params[] = { + GNUNET_SQ_query_param_auto_from_type (identity), + GNUNET_SQ_query_param_uint64 (&offset), + GNUNET_SQ_query_param_end + }; + if (GNUNET_YES == audience) + { + stmt = plugin->iterate_tickets_by_audience; + err = GNUNET_SQ_bind (stmt, + params); + } + else + { + stmt = plugin->iterate_tickets; + err = GNUNET_SQ_bind (stmt, + params); + } + if (GNUNET_OK != err) + { + LOG_SQLITE (plugin, + GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, + "sqlite3_bind_XXXX"); + GNUNET_SQ_reset (plugin->dbh, + stmt); + return GNUNET_SYSERR; + } + return get_ticket_and_call_iterator (plugin, + stmt, + iter, + iter_cls); +} + + +/** + * Entry point for the plugin. + * + * @param cls the "struct GNUNET_IDENTITY_PROVIDER_PluginEnvironment*" + * @return NULL on error, otherwise the plugin context + */ +void * +libgnunet_plugin_identity_provider_sqlite_init (void *cls) +{ + static struct Plugin plugin; + const struct GNUNET_CONFIGURATION_Handle *cfg = cls; + struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api; + + if (NULL != plugin.cfg) + return NULL; /* can only initialize once! */ + memset (&plugin, 0, sizeof (struct Plugin)); + plugin.cfg = cfg; + if (GNUNET_OK != database_setup (&plugin)) + { + database_shutdown (&plugin); + return NULL; + } + api = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_PluginFunctions); + api->cls = &plugin; + api->store_ticket = &identity_provider_sqlite_store_ticket; + api->delete_ticket = &identity_provider_sqlite_delete_ticket; + api->iterate_tickets = &identity_provider_sqlite_iterate_tickets; + api->get_ticket_attributes = &identity_provider_sqlite_ticket_get_attrs; + LOG (GNUNET_ERROR_TYPE_INFO, + _("Sqlite database running\n")); + return api; +} + + +/** + * Exit point from the plugin. + * + * @param cls the plugin context (as returned by "init") + * @return always NULL + */ +void * +libgnunet_plugin_identity_provider_sqlite_done (void *cls) +{ + struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + database_shutdown (plugin); + plugin->cfg = NULL; + GNUNET_free (api); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "sqlite plugin is finished\n"); + return NULL; +} + +/* end of plugin_identity_provider_sqlite.c */ diff --git a/src/identity-provider/plugin_rest_identity_provider.c b/src/identity-provider/plugin_rest_identity_provider.c index 907b28ba9..6eb856435 100644 --- a/src/identity-provider/plugin_rest_identity_provider.c +++ b/src/identity-provider/plugin_rest_identity_provider.c @@ -37,6 +37,7 @@ #include <jansson.h> #include <inttypes.h> #include "gnunet_signatures.h" +#include "gnunet_identity_attribute_lib.h" #include "gnunet_identity_provider_service.h" /** @@ -45,39 +46,40 @@ #define GNUNET_REST_API_NS_IDENTITY_PROVIDER "/idp" /** - * Issue namespace + * Attribute namespace */ -#define GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE "/idp/issue" +#define GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES "/idp/attributes" /** - * Check namespace TODO + * Ticket namespace */ -#define GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK "/idp/check" +#define GNUNET_REST_API_NS_IDENTITY_TICKETS "/idp/tickets" /** - * Token namespace + * Revoke namespace */ -#define GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN "/idp/token" +#define GNUNET_REST_API_NS_IDENTITY_REVOKE "/idp/revoke" /** - * The parameter name in which the ticket must be provided + * Revoke namespace */ -#define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET "ticket" +#define GNUNET_REST_API_NS_IDENTITY_CONSUME "/idp/consume" /** - * The parameter name in which the expected nonce must be provided + * Attribute key */ -#define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE "expected_nonce" +#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE "attribute" /** - * The parameter name in which the ticket must be provided + * Ticket key */ -#define GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN "token" +#define GNUNET_REST_JSONAPI_IDENTITY_TICKET "ticket" + /** - * The URL parameter name in which the nonce must be provided + * Value key */ -#define GNUNET_IDENTITY_TOKEN_REQUEST_NONCE "nonce" +#define GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE_VALUE "value" /** * State while collecting all egos @@ -89,41 +91,6 @@ */ #define ID_REST_STATE_POST_INIT 1 -/** - * Resource type - */ -#define GNUNET_REST_JSONAPI_IDENTITY_TOKEN "token" - -/** - * URL parameter to create a GNUid token for a specific audience - */ -#define GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST "audience" - -/** - * URL parameter to create a GNUid token for a specific issuer (EGO) - */ -#define GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST "issuer" - -/** - * Attributes passed to issue request - */ -#define GNUNET_IDENTITY_TOKEN_ATTR_LIST "requested_attrs" - -/** - * Token expiration string - */ -#define GNUNET_IDENTITY_TOKEN_EXP_STRING "expiration" - -/** - * Error messages - */ -#define GNUNET_REST_ERROR_RESOURCE_INVALID "Resource location invalid" -#define GNUNET_REST_ERROR_NO_DATA "No data" - -/** - * GNUid token lifetime - */ -#define GNUNET_GNUID_TOKEN_EXPIRATION_MICROSECONDS 300000000 /** * The configuration handle @@ -198,11 +165,6 @@ struct RequestHandle const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; /** - * Handle to the rest connection - */ - struct GNUNET_REST_RequestHandle *conndata_handle; - - /** * The processing state */ int state; @@ -213,6 +175,12 @@ struct RequestHandle struct GNUNET_IDENTITY_Handle *identity_handle; /** + * Rest connection + */ + struct GNUNET_REST_RequestHandle *rest_handle; + + + /** * IDENTITY Operation */ struct GNUNET_IDENTITY_Operation *op; @@ -228,19 +196,14 @@ struct RequestHandle struct GNUNET_IDENTITY_PROVIDER_Operation *idp_op; /** - * Handle to NS service - */ - struct GNUNET_NAMESTORE_Handle *ns_handle; - - /** - * NS iterator + * Attribute iterator */ - struct GNUNET_NAMESTORE_ZoneIterator *ns_it; + struct GNUNET_IDENTITY_PROVIDER_AttributeIterator *attr_it; /** - * NS Handle + * Ticket iterator */ - struct GNUNET_NAMESTORE_QueueEntry *ns_qe; + struct GNUNET_IDENTITY_PROVIDER_TicketIterator *ticket_it; /** * Desired timeout for the lookup (default is no timeout). @@ -285,6 +248,7 @@ struct RequestHandle }; + /** * Cleanup lookup handle * @param handle Handle to clean up @@ -302,14 +266,12 @@ cleanup_handle (struct RequestHandle *handle) GNUNET_SCHEDULER_cancel (handle->timeout_task); if (NULL != handle->identity_handle) GNUNET_IDENTITY_disconnect (handle->identity_handle); + if (NULL != handle->attr_it) + GNUNET_IDENTITY_PROVIDER_get_attributes_stop (handle->attr_it); + if (NULL != handle->ticket_it) + GNUNET_IDENTITY_PROVIDER_ticket_iteration_stop (handle->ticket_it); if (NULL != handle->idp) GNUNET_IDENTITY_PROVIDER_disconnect (handle->idp); - if (NULL != handle->ns_it) - GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it); - if (NULL != handle->ns_qe) - GNUNET_NAMESTORE_cancel (handle->ns_qe); - if (NULL != handle->ns_handle) - GNUNET_NAMESTORE_disconnect (handle->ns_handle); if (NULL != handle->url) GNUNET_free (handle->url); if (NULL != handle->emsg) @@ -326,6 +288,12 @@ cleanup_handle (struct RequestHandle *handle) GNUNET_free (handle); } +static void +cleanup_handle_delayed (void *cls) +{ + cleanup_handle (cls); +} + /** * Task run on error, sends error message. Cleans up everything. @@ -363,622 +331,663 @@ do_timeout (void *cls) } -/** - * Task run on shutdown. Cleans up everything. - * - * @param cls unused - */ static void -do_cleanup_handle_delayed (void *cls) +collect_error_cb (void *cls) { struct RequestHandle *handle = cls; - cleanup_handle (handle); + do_error (handle); } - -/** - * Get a ticket for identity - * @param cls the handle - * @param ticket the ticket returned from the idp - */ static void -token_creat_cont (void *cls, - const char *label, - const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket, - const struct GNUNET_IDENTITY_PROVIDER_Token *token) +finished_cont (void *cls, + int32_t success, + const char *emsg) { - struct GNUNET_JSONAPI_Resource *json_resource; struct RequestHandle *handle = cls; struct MHD_Response *resp; - json_t *ticket_json; - json_t *token_json; - char *ticket_str; - char *token_str; - char *result_str; - if (NULL == ticket) + resp = GNUNET_REST_create_response (emsg); + if (GNUNET_OK != success) { - handle->emsg = GNUNET_strdup ("Error in token issue"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_SCHEDULER_add_now (&cleanup_handle_delayed, handle); +} - handle->resp_object = GNUNET_JSONAPI_document_new (); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET, - label); - ticket_str = GNUNET_IDENTITY_PROVIDER_ticket_to_string (ticket); - token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token); - ticket_json = json_string (ticket_str); - token_json = json_string (token_str); - GNUNET_JSONAPI_resource_add_attr (json_resource, - GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET, - ticket_json); - GNUNET_JSONAPI_resource_add_attr (json_resource, - GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TOKEN, - token_json); - GNUNET_free (ticket_str); - GNUNET_free (token_str); - json_decref (ticket_json); - json_decref (token_json); - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + +/** + * Return attributes for identity + * + * @param cls the request handle + */ +static void +return_response (void *cls) +{ + char* result_str; + struct RequestHandle *handle = cls; + struct MHD_Response *resp; GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); resp = GNUNET_REST_create_response (result_str); handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); GNUNET_free (result_str); - GNUNET_SCHEDULER_add_now (&do_cleanup_handle_delayed, handle); + cleanup_handle (handle); +} + + +static void +collect_finished_cb (void *cls) +{ + struct RequestHandle *handle = cls; + //Done + handle->attr_it = NULL; + handle->ticket_it = NULL; + GNUNET_SCHEDULER_add_now (&return_response, handle); } /** - * Continueationf for token issue request + * Collect all attributes for an ego * - * @param con the Rest handle - * @param url the requested url - * @param cls the request handle */ static void -issue_token_cont (struct GNUNET_REST_RequestHandle *con, - const char *url, - void *cls) +ticket_collect (void *cls, + const struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket) { - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - const char *egoname; + struct GNUNET_JSONAPI_Resource *json_resource; + struct RequestHandle *handle = cls; + json_t *value; + char* tmp; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding ticket\n"); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TICKET, + tmp); + GNUNET_free (tmp); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "issuer", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "audience", + value); + GNUNET_free (tmp); + json_decref (value); + tmp = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, + sizeof (uint64_t)); + value = json_string (tmp); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "rnd", + value); + GNUNET_free (tmp); + json_decref (value); + GNUNET_IDENTITY_PROVIDER_ticket_iteration_next (handle->ticket_it); +} + + +/** + * List tickets for identity request + * + * @param con_handle the connection handle + * @param url the url + * @param cls the RequestHandle + */ +static void +list_tickets_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; struct RequestHandle *handle = cls; struct EgoEntry *ego_entry; - struct GNUNET_HashCode key; - struct MHD_Response *resp; - struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; - struct GNUNET_CRYPTO_EcdsaPublicKey aud_key; - struct GNUNET_TIME_Relative etime_rel; - struct GNUNET_TIME_Absolute exp_time; - char *ego_val; - char *audience; - char *exp_str; - char *nonce_str; - char *scopes; - uint64_t time; - uint64_t nonce; - - if (GNUNET_NO == GNUNET_REST_namespace_match (handle->url, - GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "URL invalid: %s\n", handle->url); - resp = GNUNET_REST_create_response (NULL); - handle->proc (handle->proc_cls, resp, MHD_HTTP_BAD_REQUEST); - cleanup_handle (handle); - return; - } - egoname = NULL; - ego_entry = NULL; - GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST, - strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST), - &key); - if ( GNUNET_YES != - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Issuer not found\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); - return; - } - ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - if (NULL == ego_val) + char *identity; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting tickets for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) >= + strlen (handle->url)) { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); GNUNET_SCHEDULER_add_now (&do_error, handle); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Ego invalid: %s\n", - ego_val); return; } + identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_TICKETS) + 1; + for (ego_entry = handle->ego_head; NULL != ego_entry; ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + handle->resp_object = GNUNET_JSONAPI_document_new (); + + if (NULL == ego_entry) { - if (0 != strcmp (ego_val, ego_entry->identifier)) - continue; - egoname = ego_entry->identifier; - break; - } - if ( (NULL == egoname) || - (NULL == ego_entry) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Ego not found: %s\n", - ego_val); - GNUNET_SCHEDULER_add_now (&do_error, handle); + //Done + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Ego to issue token for: %s\n", - egoname); + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); + handle->ticket_it = GNUNET_IDENTITY_PROVIDER_ticket_iteration_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &ticket_collect, + handle, + &collect_finished_cb, + handle); +} - //Meta info - GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_ATTR_LIST, - strlen (GNUNET_IDENTITY_TOKEN_ATTR_LIST), - &key); +static void +add_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity; + const char* name_str; + const char* value_str; - scopes = NULL; - if ( GNUNET_YES != - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attribute; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + char term_data[handle->rest_handle->data_size+1]; + json_t *value_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding an attribute for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >= + strlen (handle->url)) { - handle->emsg = GNUNET_strdup ("Scopes missing!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - scopes = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - - - //Token audience - GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST, - strlen (GNUNET_REST_JSONAPI_IDENTITY_AUD_REQUEST), - &key); - audience = NULL; - if ( GNUNET_YES != - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) + identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1; + + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; + + if (NULL == ego_entry) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Audience missing!\n"); - GNUNET_SCHEDULER_add_now (&do_error, handle); + "Identity unknown (%s)\n", identity); + GNUNET_JSONAPI_document_delete (json_obj); return; } - audience = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Audience to issue token for: %s\n", - audience); - - priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, - &pub_key); - GNUNET_STRINGS_string_to_data (audience, - strlen (audience), - &aud_key, - sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - //Remote nonce - nonce_str = NULL; - GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE, - strlen (GNUNET_IDENTITY_TOKEN_REQUEST_NONCE), - &key); - if ( GNUNET_YES != - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) + if (0 >= handle->rest_handle->data_size) { - handle->emsg = GNUNET_strdup ("Request nonce missing!\n"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - GNUNET_assert (NULL != nonce_str); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Request nonce: %s\n", - nonce_str); - GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &nonce)); - - //Get expiration for token from URL parameter - GNUNET_CRYPTO_hash (GNUNET_IDENTITY_TOKEN_EXP_STRING, - strlen (GNUNET_IDENTITY_TOKEN_EXP_STRING), - &key); - - exp_str = NULL; - if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key)) + + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) { - exp_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - } - if (NULL == exp_str) { - handle->emsg = GNUNET_strdup ("No expiration given!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - - if (GNUNET_OK != - GNUNET_STRINGS_fancy_time_to_relative (exp_str, - &etime_rel)) + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) { - handle->emsg = GNUNET_strdup ("Expiration invalid!\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - time = GNUNET_TIME_absolute_get().abs_value_us; - exp_time.abs_value_us = time + etime_rel.rel_value_us; - + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + name_str = GNUNET_JSONAPI_resource_get_id (json_res); + value_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "value"); + value_str = json_string_value (value_json); + attribute = GNUNET_IDENTITY_ATTRIBUTE_claim_new (name_str, + GNUNET_IDENTITY_ATTRIBUTE_TYPE_STRING, + value_str, + strlen (value_str) + 1); handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->idp_op = GNUNET_IDENTITY_PROVIDER_issue_token (handle->idp, - priv_key, - &aud_key, - scopes, - exp_time, - nonce, - &token_creat_cont, - handle); - -} - - -/** - * Build a GNUid token for identity - * - * @param cls the request handle - */ -static void -return_token_list (void *cls) -{ - char* result_str; - struct RequestHandle *handle = cls; - struct MHD_Response *resp; - - GNUNET_JSONAPI_document_serialize (handle->resp_object, &result_str); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Result %s\n", result_str); - resp = GNUNET_REST_create_response (result_str); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - GNUNET_free (result_str); - cleanup_handle (handle); + handle->idp_op = GNUNET_IDENTITY_PROVIDER_attribute_store (handle->idp, + identity_priv, + attribute, + &finished_cont, + handle); + GNUNET_free (attribute); + GNUNET_JSONAPI_document_delete (json_obj); } -static void -token_collect_error_cb (void *cls) -{ - struct RequestHandle *handle = cls; - - do_error (handle); -} - /** - * Collect all tokens for an ego - * - * TODO move this into the identity-provider service + * Collect all attributes for an ego * */ static void -token_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd); - - -static void -token_collect_finished_cb (void *cls) +attr_collect (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) { + struct GNUNET_JSONAPI_Resource *json_resource; struct RequestHandle *handle = cls; - struct EgoEntry *ego_tmp; - const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; - - ego_tmp = handle->ego_head; - GNUNET_CONTAINER_DLL_remove (handle->ego_head, - handle->ego_tail, - ego_tmp); - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - - if (NULL == handle->ego_head) + json_t *value; + + if ((NULL == attr->name) || (NULL == attr->data)) { - //Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token END\n"); - handle->ns_it = NULL; - GNUNET_SCHEDULER_add_now (&return_token_list, handle); + GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Next ego: %s\n", - handle->ego_head->identifier); - priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); - handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, - priv_key, - &token_collect_error_cb, - handle, - &token_collect, - handle, - &token_collect_finished_cb, - handle); -} - - -/** - * Collect all tokens for an ego - * - * TODO move this into the identity-provider service - * - */ -static void -token_collect (void *cls, - const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone, - const char *label, - unsigned int rd_count, - const struct GNUNET_GNSRECORD_Data *rd) -{ - struct RequestHandle *handle = cls; - int i; - char* data; - struct GNUNET_JSONAPI_Resource *json_resource; - json_t *issuer; - json_t *token; - - for (i = 0; i < rd_count; i++) - { - if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN) - { - data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type, - rd[i].data, - rd[i].data_size); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding token: %s\n", data); - json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_TOKEN, - label); - issuer = json_string (handle->ego_head->identifier); - GNUNET_JSONAPI_resource_add_attr (json_resource, - GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST, - issuer); - json_decref (issuer); - token = json_string (data); - GNUNET_JSONAPI_resource_add_attr (json_resource, - GNUNET_REST_JSONAPI_IDENTITY_TOKEN, - token); - json_decref (token); - - GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - GNUNET_free (data); - } - } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE, + attr->name); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); - GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it); + value = json_string (attr->data); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "value", + value); + json_decref (value); + GNUNET_IDENTITY_PROVIDER_get_attributes_next (handle->attr_it); } /** - * Respond to OPTIONS request + * List attributes for identity request * * @param con_handle the connection handle * @param url the url * @param cls the RequestHandle */ static void -list_token_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) +list_attribute_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) { - char* ego_val; - struct GNUNET_HashCode key; const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key; struct RequestHandle *handle = cls; struct EgoEntry *ego_entry; - struct EgoEntry *ego_tmp; + char *identity; - GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST, - strlen (GNUNET_REST_JSONAPI_IDENTITY_ISS_REQUEST), - &key); - - if ( GNUNET_YES != - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting attributes for %s.\n", + handle->url); + if ( strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) >= + strlen (handle->url)) { - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No issuer given.\n"); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No identity given.\n"); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - ego_val = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - GNUNET_assert (NULL != ego_val); - //Remove non-matching egos + identity = handle->url + strlen (GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES) + 1; + for (ego_entry = handle->ego_head; - NULL != ego_entry;) - { - ego_tmp = ego_entry; - ego_entry = ego_entry->next; - if (0 != strcmp (ego_val, ego_tmp->identifier)) - { - GNUNET_CONTAINER_DLL_remove (handle->ego_head, - handle->ego_tail, - ego_tmp); - GNUNET_free (ego_tmp->identifier); - GNUNET_free (ego_tmp->keystring); - GNUNET_free (ego_tmp); - } - } + NULL != ego_entry; + ego_entry = ego_entry->next) + if (0 == strcmp (identity, ego_entry->identifier)) + break; handle->resp_object = GNUNET_JSONAPI_document_new (); - if (NULL == handle->ego_head) + + + if (NULL == ego_entry) { //Done - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No results.\n"); - GNUNET_SCHEDULER_add_now (&return_token_list, handle); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ego %s not found.\n", + identity); + GNUNET_SCHEDULER_add_now (&return_response, handle); return; } - priv_key = GNUNET_IDENTITY_ego_get_private_key (handle->ego_head->ego); - handle->ns_handle = GNUNET_NAMESTORE_connect (cfg); - handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (handle->ns_handle, - priv_key, - &token_collect_error_cb, - handle, - &token_collect, - handle, - &token_collect_finished_cb, - handle); - + priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); + handle->attr_it = GNUNET_IDENTITY_PROVIDER_get_attributes_start (handle->idp, + priv_key, + &collect_error_cb, + handle, + &attr_collect, + handle, + &collect_finished_cb, + handle); } -/** - * Return token to requestor - * - * @param cls request handle - * @param token the token - */ + static void -exchange_cont (void *cls, - const struct GNUNET_IDENTITY_PROVIDER_Token *token, - uint64_t ticket_nonce) +revoke_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) { - json_t *root; + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity_str; + const char* audience_str; + const char* rnd_str; + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; struct MHD_Response *resp; - struct GNUNET_HashCode key; - char* result; - char* token_str; - char* nonce_str; - uint64_t expected_nonce; - - //Get nonce - GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE, - strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_EXPECTED_NONCE), - &key); - - if ( GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) + struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *rnd_json; + json_t *identity_json; + json_t *audience_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) { - handle->emsg = GNUNET_strdup ("No nonce given."); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - nonce_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - GNUNET_assert (NULL != nonce_str); - GNUNET_assert (1 == sscanf (nonce_str, "%"SCNu64, &expected_nonce)); - if (ticket_nonce != expected_nonce) + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Ticket nonce %"SCNu64" does not match expected nonce %"SCNu64"\n", - ticket_nonce, expected_nonce); - handle->emsg = GNUNET_strdup ("Ticket nonce does not match expected nonce\n"); + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_TICKET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "rnd"); + identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "identity"); + audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "audience"); + rnd_str = json_string_value (rnd_json); + identity_str = json_string_value (identity_json); + audience_str = json_string_value (audience_json); + + GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket.rnd, + sizeof (uint64_t)); + GNUNET_STRINGS_string_to_data (identity_str, + strlen (identity_str), + &ticket.identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + GNUNET_STRINGS_string_to_data (audience_str, + strlen (audience_str), + &ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); - root = json_object (); - token_str = GNUNET_IDENTITY_PROVIDER_token_to_string (token); - json_object_set_new (root, "token", json_string (token_str)); - json_object_set_new (root, "token_type", json_string ("jwt")); - GNUNET_free (token_str); + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket.identity, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity_str); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); - result = json_dumps (root, JSON_INDENT(1)); - resp = GNUNET_REST_create_response (result); - GNUNET_free (result); - handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); - cleanup_handle (handle); - json_decref (root); + handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); + handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_revoke (handle->idp, + identity_priv, + &ticket, + &finished_cont, + handle); + GNUNET_JSONAPI_document_delete (json_obj); } - -/** - * - * Callback called when identity for token exchange has been found - * - * @param cls request handle - * @param ego the identity to use as issuer - * @param ctx user context - * @param name identity name - * - */ static void -exchange_token_ticket_cb (void *cls, - struct GNUNET_IDENTITY_Ego *ego, - void **ctx, - const char *name) +consume_cont (void *cls, + const struct GNUNET_CRYPTO_EcdsaPublicKey *identity, + const struct GNUNET_IDENTITY_ATTRIBUTE_Claim *attr) { struct RequestHandle *handle = cls; - struct GNUNET_HashCode key; - struct GNUNET_IDENTITY_PROVIDER_Ticket *ticket; - char* ticket_str; + struct GNUNET_JSONAPI_Resource *json_resource; + json_t *value; - handle->op = NULL; + if (NULL == identity) + { + GNUNET_SCHEDULER_add_now (&return_response, handle); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", + attr->name); + json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_ATTRIBUTE, + attr->name); + GNUNET_JSONAPI_document_resource_add (handle->resp_object, json_resource); + + value = json_string (attr->data); + GNUNET_JSONAPI_resource_add_attr (json_resource, + "value", + value); + json_decref (value); +} - if (NULL == ego) +static void +consume_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, + const char* url, + void *cls) +{ + const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity_priv; + const char* identity_str; + const char* audience_str; + const char* rnd_str; + + struct RequestHandle *handle = cls; + struct EgoEntry *ego_entry; + struct MHD_Response *resp; + struct GNUNET_IDENTITY_PROVIDER_Ticket ticket; + struct GNUNET_JSONAPI_Document *json_obj; + struct GNUNET_JSONAPI_Resource *json_res; + struct GNUNET_CRYPTO_EcdsaPublicKey tmp_pk; + char term_data[handle->rest_handle->data_size+1]; + json_t *rnd_json; + json_t *identity_json; + json_t *audience_json; + json_t *data_json; + json_error_t err; + struct GNUNET_JSON_Specification docspec[] = { + GNUNET_JSON_spec_jsonapi_document (&json_obj), + GNUNET_JSON_spec_end() + }; + + if (0 >= handle->rest_handle->data_size) { - handle->emsg = GNUNET_strdup ("No identity found."); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - //Get ticket - GNUNET_CRYPTO_hash (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET, - strlen (GNUNET_REST_JSONAPI_IDENTITY_PROVIDER_TICKET), - &key); - - if ( GNUNET_NO == - GNUNET_CONTAINER_multihashmap_contains (handle->conndata_handle->url_param_map, - &key) ) + term_data[handle->rest_handle->data_size] = '\0'; + GNUNET_memcpy (term_data, + handle->rest_handle->data, + handle->rest_handle->data_size); + data_json = json_loads (term_data, + JSON_DECODE_ANY, + &err); + GNUNET_assert (GNUNET_OK == + GNUNET_JSON_parse (data_json, docspec, + NULL, NULL)); + json_decref (data_json); + if (NULL == json_obj) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unable to parse JSONAPI Object from %s\n", + term_data); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + if (1 != GNUNET_JSONAPI_document_resource_count (json_obj)) { - handle->emsg = GNUNET_strdup ("No ticket given."); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Cannot create more than 1 resource! (Got %d)\n", + GNUNET_JSONAPI_document_resource_count (json_obj)); + GNUNET_JSONAPI_document_delete (json_obj); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - ticket_str = GNUNET_CONTAINER_multihashmap_get (handle->conndata_handle->url_param_map, - &key); - handle->priv_key = GNUNET_IDENTITY_ego_get_private_key (ego); - GNUNET_IDENTITY_PROVIDER_string_to_ticket (ticket_str, - &ticket); + json_res = GNUNET_JSONAPI_document_get_resource (json_obj, 0); + if (GNUNET_NO == GNUNET_JSONAPI_resource_check_type (json_res, + GNUNET_REST_JSONAPI_IDENTITY_TICKET)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unsupported JSON data type\n"); + GNUNET_JSONAPI_document_delete (json_obj); + resp = GNUNET_REST_create_response (NULL); + handle->proc (handle->proc_cls, resp, MHD_HTTP_CONFLICT); + cleanup_handle (handle); + return; + } + rnd_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "rnd"); + identity_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "identity"); + audience_json = GNUNET_JSONAPI_resource_read_attr (json_res, + "audience"); + rnd_str = json_string_value (rnd_json); + identity_str = json_string_value (identity_json); + audience_str = json_string_value (audience_json); + + GNUNET_STRINGS_string_to_data (rnd_str, + strlen (rnd_str), + &ticket.rnd, + sizeof (uint64_t)); + GNUNET_STRINGS_string_to_data (identity_str, + strlen (identity_str), + &ticket.identity, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + GNUNET_STRINGS_string_to_data (audience_str, + strlen (audience_str), + &ticket.audience, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)); + for (ego_entry = handle->ego_head; + NULL != ego_entry; + ego_entry = ego_entry->next) + { + GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, + &tmp_pk); + if (0 == memcmp (&ticket.audience, + &tmp_pk, + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) + break; + } + if (NULL == ego_entry) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Identity unknown (%s)\n", identity_str); + GNUNET_JSONAPI_document_delete (json_obj); + return; + } + identity_priv = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego); + handle->resp_object = GNUNET_JSONAPI_document_new (); handle->idp = GNUNET_IDENTITY_PROVIDER_connect (cfg); - handle->idp_op = GNUNET_IDENTITY_PROVIDER_exchange_ticket (handle->idp, - ticket, - handle->priv_key, - &exchange_cont, - handle); - GNUNET_IDENTITY_PROVIDER_ticket_destroy (ticket); - + handle->idp_op = GNUNET_IDENTITY_PROVIDER_ticket_consume (handle->idp, + identity_priv, + &ticket, + &consume_cont, + handle); + GNUNET_JSONAPI_document_delete (json_obj); } /** - * Respond to issue request - * - * @param con_handle the connection handle - * @param url the url - * @param cls the RequestHandle - */ -static void -exchange_token_ticket_cont (struct GNUNET_REST_RequestHandle *con_handle, - const char* url, - void *cls) -{ - struct RequestHandle *handle = cls; - - //Get token from GNS - handle->op = GNUNET_IDENTITY_get (handle->identity_handle, - "gns-master", - &exchange_token_ticket_cb, - handle); -} - -/** * Respond to OPTIONS request * * @param con_handle the connection handle @@ -1013,15 +1022,17 @@ init_cont (struct RequestHandle *handle) { struct GNUNET_REST_RequestHandlerError err; static const struct GNUNET_REST_RequestHandler handlers[] = { - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TOKEN_ISSUE, &issue_token_cont}, - //{MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_TOKEN_CHECK, &check_token_cont}, - {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &list_token_cont}, - {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, &options_cont}, - {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_OAUTH2_TOKEN, &exchange_token_ticket_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &list_attribute_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_ATTRIBUTES, &add_attribute_cont}, + {MHD_HTTP_METHOD_GET, GNUNET_REST_API_NS_IDENTITY_TICKETS, &list_tickets_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_REVOKE, &revoke_ticket_cont}, + {MHD_HTTP_METHOD_POST, GNUNET_REST_API_NS_IDENTITY_CONSUME, &consume_ticket_cont}, + {MHD_HTTP_METHOD_OPTIONS, GNUNET_REST_API_NS_IDENTITY_PROVIDER, + &options_cont}, GNUNET_REST_HANDLER_END }; - if (GNUNET_NO == GNUNET_REST_handle_request (handle->conndata_handle, + if (GNUNET_NO == GNUNET_REST_handle_request (handle->rest_handle, handlers, &err, handle)) @@ -1092,19 +1103,8 @@ list_ego (void *cls, } -/** - * Function processing the REST call - * - * @param method HTTP method - * @param url URL of the HTTP request - * @param data body of the HTTP request (optional) - * @param data_size length of the body - * @param proc callback function for the result - * @param proc_cls closure for callback function - * @return GNUNET_OK if request accepted - */ static void -rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, +rest_identity_process_request(struct GNUNET_REST_RequestHandle *rest_handle, GNUNET_REST_ResultProcessor proc, void *proc_cls) { @@ -1114,10 +1114,9 @@ rest_identity_process_request(struct GNUNET_REST_RequestHandle *conndata_handle, handle->proc_cls = proc_cls; handle->proc = proc; handle->state = ID_REST_STATE_INIT; - handle->conndata_handle = conndata_handle; + handle->rest_handle = rest_handle; - - handle->url = GNUNET_strdup (conndata_handle->url); + handle->url = GNUNET_strdup (rest_handle->url); if (handle->url[strlen (handle->url)-1] == '/') handle->url[strlen (handle->url)-1] = '\0'; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -1162,8 +1161,8 @@ libgnunet_plugin_rest_identity_provider_init (void *cls) MHD_HTTP_METHOD_DELETE, MHD_HTTP_METHOD_OPTIONS); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Identity Token REST API initialized\n")); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Identity Provider REST API initialized\n")); return api; } @@ -1184,8 +1183,8 @@ libgnunet_plugin_rest_identity_provider_done (void *cls) GNUNET_free_non_null (allow_methods); GNUNET_free (api); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Identity Token REST plugin is finished\n"); + "Identity Provider REST plugin is finished\n"); return NULL; } -/* end of plugin_rest_gns.c */ +/* end of plugin_rest_identity_provider.c */ diff --git a/src/identity-provider/test_idp.conf b/src/identity-provider/test_idp.conf new file mode 100644 index 000000000..2b76c7bf2 --- /dev/null +++ b/src/identity-provider/test_idp.conf @@ -0,0 +1,28 @@ +@INLINE@ test_idp_defaults.conf + +[PATHS] +GNUNET_TEST_HOME = /tmp/test-gnunet-idp-peer-1/ + +[dht] +AUTOSTART = YES + +[rest] +AUTOSTART = YES +#PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/restlog + +[transport] +PLUGINS = + +[identity-provider] +AUTOSTART = YES +#PREFIX = valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=/tmp/idplog + +[gns] +#PREFIX = valgrind --leak-check=full --track-origins=yes +AUTOSTART = YES +AUTO_IMPORT_PKEY = YES +MAX_PARALLEL_BACKGROUND_QUERIES = 10 +DEFAULT_LOOKUP_TIMEOUT = 15 s +RECORD_PUT_INTERVAL = 1 h +ZONE_PUBLISH_TIME_WINDOW = 1 h +DNS_ROOT=PD67SGHF3E0447TU9HADIVU9OM7V4QHTOG0EBU69TFRI2LG63DR0 diff --git a/src/identity-provider/test_idp.sh b/src/identity-provider/test_idp.sh new file mode 100755 index 000000000..598d1008c --- /dev/null +++ b/src/identity-provider/test_idp.sh @@ -0,0 +1,31 @@ +#!/bin/bash +#trap "gnunet-arm -e -c test_idp_lookup.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_idp.conf +gnunet-identity -C testego -c test_idp.conf +valgrind gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf +gnunet-idp -e testego -a name -V John -c test_idp.conf +gnunet-idp -e testego -D -c test_idp.conf +gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_attribute.sh b/src/identity-provider/test_idp_attribute.sh new file mode 100755 index 000000000..7f0f06dac --- /dev/null +++ b/src/identity-provider/test_idp_attribute.sh @@ -0,0 +1,40 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_idp.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_idp.conf +#gnunet-arm -i rest -c test_idp.conf +gnunet-identity -C testego -c test_idp.conf +gnunet-identity -C rpego -c test_idp.conf +TEST_KEY=$(gnunet-identity -d -c test_idp.conf | grep testego | awk '{print $3}') +gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf +gnunet-idp -e testego -a name -V John -c test_idp.conf > /dev/null 2>&1 +if test $? != 0 +then + echo "Failed." + exit 1 +fi + +#curl localhost:7776/idp/attributes/testego +gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_consume.sh b/src/identity-provider/test_idp_consume.sh new file mode 100755 index 000000000..11f6865a4 --- /dev/null +++ b/src/identity-provider/test_idp_consume.sh @@ -0,0 +1,43 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_idp.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_idp.conf +#gnunet-arm -i rest -c test_idp.conf +gnunet-identity -C testego -c test_idp.conf +gnunet-identity -C rpego -c test_idp.conf +SUBJECT_KEY=$(gnunet-identity -d -c test_idp.conf | grep rpego | awk '{print $3}') +TEST_KEY=$(gnunet-identity -d -c test_idp.conf | grep testego | awk '{print $3}') +gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf +gnunet-idp -e testego -a name -V John -c test_idp.conf +TICKET=$(gnunet-idp -e testego -i "email,name" -r $SUBJECT_KEY -c test_idp.conf | awk '{print $1}') +gnunet-idp -e rpego -C $TICKET -c test_idp.conf > /dev/null 2>&1 + +if test $? != 0 +then + "Failed." + exit 1 +fi +#curl http://localhost:7776/idp/tickets/testego +gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_defaults.conf b/src/identity-provider/test_idp_defaults.conf new file mode 100644 index 000000000..10d89c2fb --- /dev/null +++ b/src/identity-provider/test_idp_defaults.conf @@ -0,0 +1,24 @@ +@INLINE@ ../../contrib/no_forcestart.conf + +[PATHS] +GNUNET_TEST_HOME = /tmp/test-gnunet-idp-testing/ + +[namestore-sqlite] +FILENAME = $GNUNET_TEST_HOME/namestore/sqlite_test.db + +[namecache-sqlite] +FILENAME=$GNUNET_TEST_HOME/namecache/namecache.db + +[identity] +# Directory where we store information about our egos +EGODIR = $GNUNET_TEST_HOME/identity/egos/ + +[dhtcache] +DATABASE = heap + +[transport] +PLUGINS = tcp + +[transport-tcp] +BINDTO = 127.0.0.1 + diff --git a/src/identity-provider/test_idp_issue.sh b/src/identity-provider/test_idp_issue.sh new file mode 100755 index 000000000..90487ee73 --- /dev/null +++ b/src/identity-provider/test_idp_issue.sh @@ -0,0 +1,42 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_idp.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_idp.conf +#gnunet-arm -i rest -c test_idp.conf +gnunet-identity -C testego -c test_idp.conf +gnunet-identity -C rpego -c test_idp.conf +SUBJECT_KEY=$(gnunet-identity -d -c test_idp.conf | grep rpego | awk '{print $3}') +TEST_KEY=$(gnunet-identity -d -c test_idp.conf | grep testego | awk '{print $3}') +gnunet-idp -e testego -a email -V john@doe.gnu -c test_idp.conf > /dev/null 2>&1 +gnunet-idp -e testego -a name -V John -c test_idp.conf > /dev/null 2>&1 +#gnunet-idp -e testego -D -c test_idp.conf +gnunet-idp -e testego -i "email,name" -r $SUBJECT_KEY -c test_idp.conf > /dev/null 2>&1 +if test $? != 0 +then + echo "Failed." + exit 1 +fi +#curl http://localhost:7776/idp/attributes/testego +gnunet-arm -e -c test_idp.conf diff --git a/src/identity-provider/test_idp_revoke.sh b/src/identity-provider/test_idp_revoke.sh new file mode 100755 index 000000000..d5c2c3f77 --- /dev/null +++ b/src/identity-provider/test_idp_revoke.sh @@ -0,0 +1,60 @@ +#!/bin/bash +trap "gnunet-arm -e -c test_idp.conf" SIGINT + +LOCATION=$(which gnunet-config) +if [ -z $LOCATION ] +then + LOCATION="gnunet-config" +fi +$LOCATION --version 1> /dev/null +if test $? != 0 +then + echo "GNUnet command line tools cannot be found, check environmental variables PATH and GNUNET_PREFIX" + exit 77 +fi + +rm -rf `gnunet-config -c test_idp.conf -s PATHS -o GNUNET_HOME -f` + +# (1) PKEY1.user -> PKEY2.resu.user +# (2) PKEY2.resu -> PKEY3 +# (3) PKEY3.user -> PKEY4 + + +which timeout &> /dev/null && DO_TIMEOUT="timeout 30" + +TEST_ATTR="test" +gnunet-arm -s -c test_idp.conf +gnunet-identity -C alice -c test_idp.conf +gnunet-identity -C bob -c test_idp.conf +gnunet-identity -C eve -c test_idp.conf +ALICE_KEY=$(gnunet-identity -d -c test_idp.conf | grep alice | awk '{print $3}') +BOB_KEY=$(gnunet-identity -d -c test_idp.conf | grep bob | awk '{print $3}') +EVE_KEY=$(gnunet-identity -d -c test_idp.conf | grep eve | awk '{print $3}') + +gnunet-idp -e alice -a email -V john@doe.gnu -c test_idp.conf +gnunet-idp -e alice -a name -V John -c test_idp.conf +TICKET_BOB=$(gnunet-idp -e alice -i "email,name" -r $BOB_KEY -c test_idp.conf | awk '{print $1}') +#gnunet-idp -e bob -C $TICKET_BOB -c test_idp.conf +TICKET_EVE=$(gnunet-idp -e alice -i "email" -r $EVE_KEY -c test_idp.conf | awk '{print $1}') + + +#echo "Consuming $TICKET" +#gnunet-idp -e eve -C $TICKET_EVE -c test_idp.conf +gnunet-idp -e alice -R $TICKET_EVE -c test_idp.conf + +gnunet-idp -e eve -C $TICKET_EVE -c test_idp.conf > /dev/null 2>&1 +if test $? == 0 +then + echo "Eve can still resolve attributes..." + gnunet-arm -e -c test_idp.conf + exit 1 +fi +gnunet-idp -e bob -C $TICKET_BOB -c test_idp.conf > /dev/null 2>&1 +if test $? != 0 +then + echo "Bob cannot resolve attributes..." + gnunet-arm -e -c test_idp.conf + exit 1 +fi + +gnunet-arm -e -c test_idp.conf diff --git a/src/identity/Makefile.am b/src/identity/Makefile.am index 94e8c5e94..b8e70fffb 100644 --- a/src/identity/Makefile.am +++ b/src/identity/Makefile.am @@ -42,8 +42,7 @@ libexec_PROGRAMS = \ if HAVE_MHD if HAVE_JSON plugin_LTLIBRARIES = \ - libgnunet_plugin_rest_identity.la \ - libgnunet_plugin_gnsrecord_identity.la + libgnunet_plugin_rest_identity.la endif endif @@ -55,14 +54,6 @@ gnunet_service_identity_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(GN_LIBINTL) -libgnunet_plugin_gnsrecord_identity_la_SOURCES = \ - plugin_gnsrecord_identity.c -libgnunet_plugin_gnsrecord_identity_la_LIBADD = \ - $(top_builddir)/src/util/libgnunetutil.la \ - $(LTLIBINTL) -libgnunet_plugin_gnsrecord_identity_la_LDFLAGS = \ - $(GN_PLUGIN_LDFLAGS) - libgnunet_plugin_rest_identity_la_SOURCES = \ plugin_rest_identity.c diff --git a/src/identity/plugin_rest_identity.c b/src/identity/plugin_rest_identity.c index e64b2685a..5f34d0f1b 100644 --- a/src/identity/plugin_rest_identity.c +++ b/src/identity/plugin_rest_identity.c @@ -427,9 +427,6 @@ ego_info_response (struct GNUNET_REST_RequestHandle *con, continue; json_resource = GNUNET_JSONAPI_resource_new (GNUNET_REST_JSONAPI_IDENTITY_EGO, ego_entry->keystring); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Egoname: %s\n", - ego_entry->identifier); name_str = json_string (ego_entry->identifier); GNUNET_JSONAPI_resource_add_attr ( json_resource, diff --git a/src/include/gnunet_abe_lib.h b/src/include/gnunet_abe_lib.h new file mode 100644 index 000000000..f73ea2431 --- /dev/null +++ b/src/include/gnunet_abe_lib.h @@ -0,0 +1,193 @@ +/* + This file is part of GNUnet. + Copyright (C) 2001-2018 GNUnet e.V. + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +/** + * @file include/gnunet_abe_lib.h + * @brief Attribute-Based Encryption primitives for GNUnet + * + * @author Martin Schanzenbach + * + * @defgroup abe ABE Crypto library: Attribute-Based Encryption operations + * + */ +#ifndef GNUNET_ABE_LIB_H +#define GNUNET_ABE_LIB_H + +#ifdef __cplusplus +extern "C" +{ +#if 0 /* keep Emacsens' auto-indent happy */ +} +#endif +#endif + +#include "gnunet_common.h" +#include <gcrypt.h> + +/** + * @brief type for ABE master keys + */ +struct GNUNET_CRYPTO_AbeMasterKey; + +/** + * @brief type for ABE keys + */ +struct GNUNET_CRYPTO_AbeKey; + + + +/** + * @ingroup abe + * Create a new CP-ABE master key. Caller must free return value. + * + * @return fresh private key; free using #GNUNET_ABE_cpabe_delete_master_key + */ +struct GNUNET_ABE_AbeMasterKey * +GNUNET_ABE_cpabe_create_master_key (void); + +/** + * @ingroup abe + * Delete a CP-ABE master key. + * + * @param key the master key + * @return fresh private key; free using #GNUNET_free + */ +void +GNUNET_ABE_cpabe_delete_master_key (struct GNUNET_ABE_AbeMasterKey *key); + +/** + * @ingroup abe + * Create a new CP-ABE key. Caller must free return value. + * + * @param key the master key + * @param attrs the attributes to append to the key + * @return fresh private key; free using #GNUNET_ABE_cpabe_delete_key + */ +struct GNUNET_ABE_AbeKey * +GNUNET_ABE_cpabe_create_key (struct GNUNET_ABE_AbeMasterKey *key, + char **attrs); + +/** + * @ingroup abe + * Delete a CP-ABE key. + * + * @param key the key to delete + * @param delete_pub GNUNE_YES if the public key should also be freed (bug in gabe) + * @return fresh private key; free using #GNUNET_free + */ +void +GNUNET_ABE_cpabe_delete_key (struct GNUNET_ABE_AbeKey *key, + int delete_pub); + + +/** + * @ingroup abe + * Encrypt a block using sessionkey. + * + * @param block the block to encrypt + * @param size the size of the @a block + * @param policy the ABE policy + * @param key the key used to encrypt + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_encrypt (const void *block, + size_t size, + const char *policy, + const struct GNUNET_ABE_AbeMasterKey *key, + void **result); + +/** + * @ingroup abe + * Decrypt a block using the ABE key. + * + * @param block the block to encrypt + * @param size the size of the @a block + * @param key the key used to decrypt + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_decrypt (const void *block, + size_t size, + const struct GNUNET_ABE_AbeKey *key, + void **result); + +/** + * @ingroup abe + * Serialize an ABE key. + * + * @param key the key to serialize + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_serialize_key (const struct GNUNET_ABE_AbeKey *key, + void **result); + +/** + * @ingroup abe + * Deserialize a serialized ABE key. + * + * @param data the data to deserialize + * @param len the length of the data. + * @return the ABE key. NULL of unsuccessful + */ +struct GNUNET_ABE_AbeKey* +GNUNET_ABE_cpabe_deserialize_key (const void *data, + size_t len); + +/** + * @ingroup abe + * Serialize an ABE master key. + * + * @param key the key to serialize + * @param result the result buffer. Will be allocated. Free using #GNUNET_free + * @return the size of the encrypted block, -1 for errors + */ +ssize_t +GNUNET_ABE_cpabe_serialize_master_key (const struct GNUNET_ABE_AbeMasterKey *key, + void **result); + +/** + * @ingroup abe + * Deserialize an ABE master key. + * + * @param data the data to deserialize + * @param len the length of the data. + * @return the ABE key. NULL of unsuccessful + */ +struct GNUNET_ABE_AbeMasterKey* +GNUNET_ABE_cpabe_deserialize_master_key (const void *data, + size_t len); + + +#if 0 /* keep Emacsens' auto-indent happy */ +{ +#endif +#ifdef __cplusplus +} +#endif + + +/* ifndef GNUNET_ABE_LIB_H */ +#endif +/* end of gnunet_abe_lib.h */ diff --git a/src/include/gnunet_credential_service.h b/src/include/gnunet_credential_service.h index 9e765c12b..7d6f9e973 100644 --- a/src/include/gnunet_credential_service.h +++ b/src/include/gnunet_credential_service.h @@ -34,6 +34,7 @@ #include "gnunet_util_lib.h" #include "gnunet_gns_service.h" +#include "gnunet_identity_service.h" #ifdef __cplusplus extern "C" @@ -52,7 +53,157 @@ struct GNUNET_CREDENTIAL_Handle; /** * Handle to control a lookup operation. */ -struct GNUNET_CREDENTIAL_LookupRequest; +struct GNUNET_CREDENTIAL_Request; + +/* +* Enum used for checking whether the issuer has the authority to issue credentials or is just a subject +*/ +enum GNUNET_CREDENTIAL_CredentialFlags { + + //Subject had credentials before, but have been revoked now + GNUNET_CREDENTIAL_FLAG_REVOKED=0, + + //Subject flag indicates that the subject is a holder of this credential and may present it as such + GNUNET_CREDENTIAL_FLAG_SUBJECT=1, + + //Issuer flag is used to signify that the subject is allowed to issue this credential and delegate issuance + GNUNET_CREDENTIAL_FLAG_ISSUER=2 + +}; + +GNUNET_NETWORK_STRUCT_BEGIN +/** + * The attribute delegation record + */ +struct GNUNET_CREDENTIAL_DelegationRecord { + + /** + * Number of delegation sets in this record + */ + uint32_t set_count; + + /** + * Length of delegation sets + */ + uint64_t data_size; + /** + * Followed by set_count DelegationSetRecords + * + */ +}; + +/** + * The attribute delegation record + */ +struct GNUNET_CREDENTIAL_DelegationRecordSet { + + /** + * Public key of the subject this attribute was delegated to + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Length of attribute, may be 0 + */ + uint32_t subject_attribute_len; +}; + + +GNUNET_NETWORK_STRUCT_END + +/** + * The attribute delegation record + */ +struct GNUNET_CREDENTIAL_DelegationSet { + + /** + * Public key of the subject this attribute was delegated to + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + uint32_t subject_attribute_len; + + /** + * The subject attribute + */ + const char *subject_attribute; +}; + + +/** + * A delegation + */ +struct GNUNET_CREDENTIAL_Delegation { + + /** + * The issuer of the delegation + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Public key of the subject this attribute was delegated to + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Length of the attribute + */ + uint32_t issuer_attribute_len; + + /** + * The attribute + */ + const char *issuer_attribute; + + /** + * Length of the attribute + */ + uint32_t subject_attribute_len; + + /** + * The attribute + */ + const char *subject_attribute; +}; + + +/** + * A credential + */ +struct GNUNET_CREDENTIAL_Credential { + + /** + * The issuer of the credential + */ + struct GNUNET_CRYPTO_EcdsaPublicKey issuer_key; + + /** + * Public key of the subject this credential was issued to + */ + struct GNUNET_CRYPTO_EcdsaPublicKey subject_key; + + /** + * Signature of this credential + */ + struct GNUNET_CRYPTO_EcdsaSignature signature; + + /** + * Expiration of this credential + */ + struct GNUNET_TIME_Absolute expiration; + + /** + * Length of the attribute + */ + uint32_t issuer_attribute_len; + + /** + * The attribute + */ + const char *issuer_attribute; + +}; + /** @@ -61,7 +212,7 @@ struct GNUNET_CREDENTIAL_LookupRequest; * @param cfg configuration to use * @return handle to the Credential service, or NULL on error */ -struct GNUNET_Credential_Handle * +struct GNUNET_CREDENTIAL_Handle * GNUNET_CREDENTIAL_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); @@ -75,73 +226,131 @@ GNUNET_CREDENTIAL_disconnect (struct GNUNET_CREDENTIAL_Handle *handle); /** - * Iterator called on obtained result for a Credential lookup. + * Iterator called on obtained result for an attribute verification. + * + * @param cls closure + * @param d_count the number of delegations processed + * @param delegation_chain the delegations processed + * @param c_count the number of credentials found + * @param credential the credentials + */ +typedef void (*GNUNET_CREDENTIAL_CredentialResultProcessor) (void *cls, + unsigned int d_count, + struct GNUNET_CREDENTIAL_Delegation *delegation_chain, + unsigned int c_count, + struct GNUNET_CREDENTIAL_Credential *credential); + +/** + * Iterator called on obtained result for an attribute delegation. + * + * @param cls closure + * @param success GNUNET_YES if successful + * @param result the record data that can be handed to the subject + */ +typedef void (*GNUNET_CREDENTIAL_DelegateResultProcessor) (void *cls, + uint32_t success); + +/** + * Iterator called on obtained result for an attribute delegation removal. * * @param cls closure - * @param issuer the issuer chain - * @param issuer_len length of issuer chain - * @param value the value returned + * @param success GNUNET_YES if successful + * @param result the record data that can be handed to the subject */ -typedef void -(*GNUNET_CREDENTIAL_LookupResultProcessor) (void *cls, - struct GNUNET_IDENTITY_Ego *issuer, - uint16_t issuer_len, - const struct GNUNET_CREDENTIAL_Value *value); +typedef void (*GNUNET_CREDENTIAL_RemoveDelegateResultProcessor) (void *cls, + uint32_t success); /** - * Perform an asynchronous lookup operation for a credential. + * Performs attribute verification. + * Checks if there is a delegation chain from + * attribute ``issuer_attribute'' issued by the issuer + * with public key ``issuer_key'' maps to the attribute + * ``subject_attribute'' claimed by the subject with key + * ``subject_key'' * * @param handle handle to the Credential service - * @param credential the credential to look up - * @param subject Ego to check the credential for + * @param issuer_key the issuer public key + * @param issuer_attribute the issuer attribute + * @param subject_key the subject public key + * @param credential_count number of credentials + * @param credentials the subject credentials * @param proc function to call on result * @param proc_cls closure for processor * @return handle to the queued request */ -struct GNUNET_CREDENTIAL_LookupRequest * -GNUNET_CREDENTIAL_lookup (struct GNUNET_CREDENTIAL_Handle *handle, - const char *credential, - const struct GNUNET_IDENTITY_Ego *subject, - GNUNET_CREDENTIAL_LookupResultProcessor proc, +struct GNUNET_CREDENTIAL_Request* +GNUNET_CREDENTIAL_verify (struct GNUNET_CREDENTIAL_Handle *handle, + const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key, + const char *issuer_attribute, + const struct GNUNET_CRYPTO_EcdsaPublicKey *subject_key, + uint32_t credential_count, + const struct GNUNET_CREDENTIAL_Credential *credentials, + GNUNET_CREDENTIAL_CredentialResultProcessor proc, void *proc_cls); +struct GNUNET_CREDENTIAL_Request* +GNUNET_CREDENTIAL_collect (struct GNUNET_CREDENTIAL_Handle *handle, + const struct GNUNET_CRYPTO_EcdsaPublicKey *issuer_key, + const char *issuer_attribute, + const struct GNUNET_CRYPTO_EcdsaPrivateKey *subject_key, + GNUNET_CREDENTIAL_CredentialResultProcessor proc, + void *proc_cls); /** - * Issue a credential to an identity + * Delegate an attribute * * @param handle handle to the Credential service - * @param issuer the identity that issues the credential - * @param subject the subject of the credential - * @param credential the name of the credential - * @param value the value of the credential + * @param issuer the ego that should be used to delegate the attribute + * @param attribute the name of the attribute to delegate + * @param subject the subject of the delegation + * @param delegated_attribute the name of the attribute that is delegated to + * @param proc the result callback + * @param proc_cls the result closure context * @return handle to the queued request */ -struct GNUNET_CREDENTIAL_IssueRequest * -GNUNET_CREDENTIAL_issue (struct GNUNET_CREDENTIAL_Handle *handle, - struct GNUNET_IDENTITY_Ego *issuer, - struct GNUNET_IDENTITY_Ego *subject, - const char *credential, - struct GNUNET_CREDENTIAL_Value *value, - GNUNET_CREDENTIAL_IssueResultProcessor proc, - void *proc_cls); +struct GNUNET_CREDENTIAL_Request * +GNUNET_CREDENTIAL_add_delegation (struct GNUNET_CREDENTIAL_Handle *handle, + struct GNUNET_IDENTITY_Ego *issuer, + const char *attribute, + struct GNUNET_CRYPTO_EcdsaPublicKey *subject, + const char *delegated_attribute, + GNUNET_CREDENTIAL_DelegateResultProcessor proc, + void *proc_cls); /** - * Remove a credential + * Remove a delegation * * @param handle handle to the Credential service - * @param issuer the identity that issued the credential - * @param subject the subject of the credential - * @param credential the name of the credential + * @param issuer the ego that was used to delegate the attribute |