diff --git a/repos/libports/lib/import/import-libgcrypt.mk b/repos/libports/lib/import/import-libgcrypt.mk new file mode 100644 index 0000000000..333fd8044e --- /dev/null +++ b/repos/libports/lib/import/import-libgcrypt.mk @@ -0,0 +1 @@ +INC_DIR += $(call select_from_ports,libgcrypt)/include/libgcrypt diff --git a/repos/libports/lib/mk/libgcrypt.mk b/repos/libports/lib/mk/libgcrypt.mk new file mode 100644 index 0000000000..ef740f9aa6 --- /dev/null +++ b/repos/libports/lib/mk/libgcrypt.mk @@ -0,0 +1,34 @@ +LIBGCRYPT_DIR := $(call select_from_ports,libgcrypt)/src/lib/libgcrypt +LIBGCRYPT_SRC_DIR := $(LIBGCRYPT_DIR)/src + +LIBS := libc libgpg-error + +SRC_C := global.c stdmem.c visibility.c fips.c misc.c secmem.c md.c cipher.c \ + random.c random-csprng.c poly1305.c rndjent.c pubkey.c random-drbg.c \ + primegen.c random-system.c sha1.c mac.c hmac-tests.c mac-poly1305.c \ + hwfeatures.c hmac256.c blake2.c rndhw.c hash-common.c sexp.c \ + mac-hmac.c rsa.c rsa-common.c pubkey-util.c sha256.c + +SRC_C += $(notdir $(wildcard $(LIBGCRYPT_DIR)/mpi/mpi*.c)) +SRC_C += $(notdir $(wildcard $(LIBGCRYPT_DIR)/mpi/generic/*.c)) +SRC_C += $(notdir $(wildcard $(LIBGCRYPT_DIR)/cipher/cipher-*.c)) + +INC_DIR += $(REP_DIR)/src/lib/libgcrypt +INC_DIR += $(REP_DIR)/src/lib/libgcrypt/mpi +INC_DIR += $(LIBGCRYPT_SRC_DIR) +INC_DIR += $(LIBGCRYPT_DIR)/mpi +INC_DIR += $(call select_from_ports,libgcrypt)/include/libgcrypt + +CC_OPT += -D_GCRYPT_IN_LIBGCRYPT +CC_OPT += -DVERSION='"$(< $(LIBGCRYPT_DIR))"' +CC_OPT += -DLIBGCRYPT_CIPHERS='"rsa"' +CC_OPT += -DLIBGCRYPT_PUBKEY_CIPHERS='"rsa"' +CC_OPT += -DLIBGCRYPT_DIGESTS='""' + +CC_OPT_global += -Wno-switch + +vpath %.c $(LIBGCRYPT_SRC_DIR) +vpath %.c $(LIBGCRYPT_DIR)/cipher +vpath %.c $(LIBGCRYPT_DIR)/random +vpath %.c $(LIBGCRYPT_DIR)/mpi +vpath %.c $(LIBGCRYPT_DIR)/mpi/generic diff --git a/repos/libports/lib/mk/libgpg-error.mk b/repos/libports/lib/mk/libgpg-error.mk new file mode 100644 index 0000000000..92ecb8f675 --- /dev/null +++ b/repos/libports/lib/mk/libgpg-error.mk @@ -0,0 +1,15 @@ +LIBGPG_ERROR_DIR := $(call select_from_ports,libgcrypt)/src/lib/libgpg-error +LIBGPG_ERROR_SRC_DIR := $(LIBGPG_ERROR_DIR)/src + +LIBS := libc + +SRC_C := visibility.c code-from-errno.c init.c estream.c estream-printf.c \ + strerror.c code-to-errno.c posix-lock.c posix-thread.c + +INC_DIR += $(REP_DIR)/src/lib/libgpg-error $(LIBGPG_ERROR_SRC_DIR) + +CC_OPT += -DHAVE_CONFIG_H + +include $(REP_DIR)/lib/import/import-libgcrypt.mk + +vpath %.c $(LIBGPG_ERROR_SRC_DIR) diff --git a/repos/libports/ports/libgcrypt.hash b/repos/libports/ports/libgcrypt.hash new file mode 100644 index 0000000000..ea616459e9 --- /dev/null +++ b/repos/libports/ports/libgcrypt.hash @@ -0,0 +1 @@ +c9c155548be98de2f3fcf27400838caaee3db765 diff --git a/repos/libports/ports/libgcrypt.port b/repos/libports/ports/libgcrypt.port new file mode 100644 index 0000000000..1d36bd8de6 --- /dev/null +++ b/repos/libports/ports/libgcrypt.port @@ -0,0 +1,83 @@ +LICENSE := LGPLv2.1+ +VERSION := 1.8.2 +DOWNLOADS := libgcrypt.archive libgpg-error.archive + +COMMON_URL := https://www.gnupg.org/ftp/gcrypt + +URL(libgcrypt) := $(COMMON_URL)/libgcrypt/libgcrypt-$(VERSION).tar.bz2 +SHA(libgcrypt) := ab8aae5d7a68f8e0988f90e11e7f6a4805af5c8d +DIR(libgcrypt) := src/lib/libgcrypt + +LIBGPG_ERROR_VERSION := 1.27 + +URL(libgpg-error) := $(COMMON_URL)/libgpg-error/libgpg-error-$(LIBGPG_ERROR_VERSION).tar.bz2 +SHA(libgpg-error) := a428758999ff573e62d06892e3d2c0b0f335787c +DIR(libgpg-error) := src/lib/libgpg-error + +HASH_INPUT += $(REP_DIR)/src/lib/libgpg-error/config.h + +$(call check_tool,mawk) + +gen_files := include/libgcrypt/gcrypt.h \ + include/libgcrypt/gpg-error.h \ + src/lib/libgpg-error/src/code-from-errno.h \ + src/lib/libgpg-error/src/code-to-errno.h + +default: $(gen_files) + +$(gen_files): $(DOWNLOADS) + +# obtain 'VERSION_NUMBER' definition from configure script +version_number = $(shell sed -n "/VERSION_NUMBER=/s/.*=//p" $1/configure) + +subst_gcrypt = \ + "@INSERT_SYS_SELECT_H@/include " \ + "@FALLBACK_SOCKLEN_T@/" \ + "@VERSION@/\"$(VERSION)\"" \ + "@VERSION_NUMBER@/$(call version_number,src/lib/libgcrypt)" + +apply_substitutions = $(VERBOSE)for i in $(1); do sed -i "s/$$i/g" $(2); done + +include/libgcrypt/gcrypt.h: + @$(MSG_GENERATE)$@ + $(VERBOSE)mkdir -p $(dir $@) + $(VERBOSE)cp src/lib/libgcrypt/src/gcrypt.h.in $@ + $(call apply_substitutions,$(subst_gcrypt),$@) + +include/libgcrypt/gpg-error.h: mkheader + @$(MSG_GENERATE)$@ + $(VERBOSE)mkdir -p $(dir $@) + $(VERBOSE)cp src/lib/libgpg-error/src/syscfg/lock-obj-pub.x86_64-pc-kfreebsd-gnu.h \ + lock-obj-pub.native.h + $(VERBOSE)./mkheader unknown-host-os host-triplet-unknown \ + src/lib/libgpg-error/src/gpg-error.h.in \ + $(REP_DIR)/src/lib/libgpg-error/config.h \ + $(LIBGPG_ERROR_VERSION) $(call version_number,src/lib/libgpg-error) >$@ + $(VERBOSE)rm lock-obj-pub.native.h mkheader + +src/lib/libgpg-error/src/code-from-errno.h: mkerrcodes + @$(MSG_GENERATE)$@ + $(VERBOSE)mkdir -p $(dir $@) + $(VERBOSE)./mkerrcodes | nawk -f src/lib/libgpg-error/src/mkerrcodes2.awk > $@ + $(VERBOSE)rm mkerrcodes + +src/lib/libgpg-error/src/code-to-errno.h: + @$(MSG_GENERATE)$@ + $(VERBOSE)nawk -f src/lib/libgpg-error/src/mkerrnos.awk src/lib/libgpg-error/src/errnos.in > $@ + +mkheader: $(DOWNLOADS) + $(VERBOSE)$(CC) -g -Isrc/lib/libgpg-error/src \ + src/lib/libgpg-error/src/mkheader.c -o $@ + +mkerrcodes: $(DOWNLOADS) src/lib/libgpg-error/src/mkerrcodes.h + $(VERBOSE)$(CC) -g -Isrc/lib/libgpg-error/src \ + src/lib/libgpg-error/src/mkerrcodes.c -o $@ + +src/lib/libgpg-error/src/mkerrcodes.h: + @$(MSG_GENERATE)$@ + $(VERBOSE)nawk -f src/lib/libgpg-error/src/mkerrcodes1.awk \ + src/lib/libgpg-error/src/errnos.in |\ + $(CPP) -P - |\ + grep GPG_ERR_ |\ + nawk -f src/lib/libgpg-error/src/mkerrcodes.awk > $@ + diff --git a/repos/libports/recipes/api/libgcrypt/content.mk b/repos/libports/recipes/api/libgcrypt/content.mk new file mode 100644 index 0000000000..4af464571d --- /dev/null +++ b/repos/libports/recipes/api/libgcrypt/content.mk @@ -0,0 +1,31 @@ +content: src/lib/libgcrypt src/lib/libgpg-error include lib/mk lib/import LICENSE + +LIBGCRYPT_DIR := $(call port_dir,$(REP_DIR)/ports/libgcrypt) +LIBGCRYPT_SRC_DIR := $(LIBGCRYPT_DIR)/src/lib/libgcrypt + +include: + cp -r $(LIBGCRYPT_DIR)/include/libgcrypt $@ + +src/lib/libgcrypt: + mkdir -p $@ + cp -r $(addprefix $(LIBGCRYPT_SRC_DIR)/,src mpi cipher random compat) $@ + cp $(REP_DIR)/src/lib/libgcrypt/config.h $@ + cp $(REP_DIR)/src/lib/libgcrypt/mod-source-info.h $@ + cp $(REP_DIR)/src/lib/libgcrypt/mpi/mpi-asm-defs.h $@/mpi + +src/lib/libgpg-error: + mkdir -p $@ + cp -r $(LIBGCRYPT_DIR)/src/lib/libgpg-error/src $@ + cp $(REP_DIR)/src/lib/libgpg-error/config.h $@ + +lib/mk: + mkdir -p $@ + cp $(addprefix $(REP_DIR)/lib/mk/,libgpg-error.mk libgcrypt.mk) $@ + +lib/import: + mkdir -p $@ + cp $(REP_DIR)/lib/import/import-libgcrypt.mk $@ + +LICENSE: + cp $(LIBGCRYPT_SRC_DIR)/COPYING $@ + diff --git a/repos/libports/recipes/api/libgcrypt/hash b/repos/libports/recipes/api/libgcrypt/hash new file mode 100644 index 0000000000..3a2735d49b --- /dev/null +++ b/repos/libports/recipes/api/libgcrypt/hash @@ -0,0 +1 @@ +2018-01-11 5d8f799b6f0c03d4d1697da40c858d878b2e3664 diff --git a/repos/libports/src/lib/libgcrypt/config.h b/repos/libports/src/lib/libgcrypt/config.h new file mode 100644 index 0000000000..81ded4abcb --- /dev/null +++ b/repos/libports/src/lib/libgcrypt/config.h @@ -0,0 +1,21 @@ +#define _GCRYPT_CONFIG_H_INCLUDED 1 + +#define HAVE_STDINT_H 1 +#define HAVE_CLOCK_GETTIME 1 +#define HAVE_GETPID 1 +#define HAVE_CLOCK 1 + +#ifdef __LP64__ +#define SIZEOF_UNSIGNED_SHORT 2 +#define SIZEOF_UNSIGNED_INT 4 +#define SIZEOF_UNSIGNED_LONG 8 +#else +#define SIZEOF_UNSIGNED_SHORT 2 +#define SIZEOF_UNSIGNED_INT 4 +#define SIZEOF_UNSIGNED_LONG 4 +#define SIZEOF_UNSIGNED_LONG_LONG 8 +#endif + +#define USE_SHA1 1 +#define USE_SHA256 1 +#define USE_RSA 1 diff --git a/repos/libports/src/lib/libgcrypt/local_install.mk b/repos/libports/src/lib/libgcrypt/local_install.mk new file mode 100644 index 0000000000..4cc7d9a695 --- /dev/null +++ b/repos/libports/src/lib/libgcrypt/local_install.mk @@ -0,0 +1,48 @@ +# +# This is a convenience helper for porting libgcrypt. It downloads and builds +# libgcrypt and libgpg-error within the current working directory and thereby +# makes generated files like config.h readily available. +# + +default: install_libgcrypt + +PWD := $(shell pwd) + +LIBGRYPT := libgcrypt-1.8.2 +LIBGPG_ERROR := libgpg-error-1.27 + +INSTALL_DIR := $(PWD)/install + +URL(${LIBGRYPT}) := https://www.gnupg.org/ftp/gcrypt/libgcrypt/$(LIBGRYPT).tar.bz2 +URL(${LIBGPG_ERROR}) := https://www.gnupg.org/ftp/gcrypt/libgpg-error/$(LIBGPG_ERROR).tar.bz2 + +install/include/gpg-error.h: build/$(LIBGPG_ERROR)/Makefile + cd build/$(LIBGPG_ERROR); $(MAKE) install + +install_libgcrypt: build/$(LIBGRYPT)/Makefile + cd build/$(LIBGRYPT); $(MAKE) install + +build/$(LIBGRYPT)/Makefile : src/$(LIBGRYPT) build/$(LIBGRYPT) install/include/gpg-error.h + cd build/$(LIBGRYPT); \ + $(PWD)/src/$(LIBGRYPT)/configure --prefix=$(INSTALL_DIR) \ + --with-libgpg-error-prefix=$(INSTALL_DIR) + +build/$(LIBGPG_ERROR)/Makefile : src/$(LIBGPG_ERROR) build/$(LIBGPG_ERROR) + cd build/$(LIBGPG_ERROR); \ + $(PWD)/src/$(LIBGPG_ERROR)/configure --prefix=$(INSTALL_DIR) + +build/%: + mkdir -p $@ + +src/% : %.tar.bz2 + mkdir -p src + cd src; tar xf $(PWD)/$< + +%.tar.bz2: + wget ${URL($*)} + +clean: + rm -rf install build src + +cleanall: clean + rm *.tar.bz2 diff --git a/repos/libports/src/lib/libgcrypt/mod-source-info.h b/repos/libports/src/lib/libgcrypt/mod-source-info.h new file mode 100644 index 0000000000..3408ed32e5 --- /dev/null +++ b/repos/libports/src/lib/libgcrypt/mod-source-info.h @@ -0,0 +1 @@ +static char mod_source_info[] = ""; diff --git a/repos/libports/src/lib/libgcrypt/mpi/mpi-asm-defs.h b/repos/libports/src/lib/libgcrypt/mpi/mpi-asm-defs.h new file mode 100644 index 0000000000..7a9ed36d8b --- /dev/null +++ b/repos/libports/src/lib/libgcrypt/mpi/mpi-asm-defs.h @@ -0,0 +1,7 @@ +/* + * 'libgcrypt/src/mpi.h' unconditionally includes "../mpi/mpi-asm-defs.h"/ + * We need to direct it to one of the architecture-specific versions at + * 'libgcrypt/mpi//'. + */ + +#include <../mpi/generic/mpi-asm-defs.h> diff --git a/repos/libports/src/lib/libgpg-error/config.h b/repos/libports/src/lib/libgpg-error/config.h new file mode 100644 index 0000000000..1a03016866 --- /dev/null +++ b/repos/libports/src/lib/libgpg-error/config.h @@ -0,0 +1,32 @@ +#define BUILD_REVISION "0" +#define BUILD_TIMESTAMP "" +#define HAVE_DECL_STRERROR_R 1 +#define HAVE_DLFCN_H 1 +#define HAVE_GCC_ATTRIBUTE_ALIGNED 1 +#define HAVE_INTMAX_T 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LONG_LONG_INT 1 +#define HAVE_MEMORY_H 1 +#define HAVE_MEMRCHR 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRERROR_R 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UINTMAX_T 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UNSIGNED_LONG_LONG_INT 1 +#define HOST_TRIPLET_STRING "unknown-host-triplet" +#define PACKAGE "libgpg-error" +#define PACKAGE_NAME "libgpg-error" +#define PACKAGE_VERSION "1.27" +#define REPLACEMENT_FOR_OFF_T "long" +#define STDC_HEADERS 1 +#define TIME_WITH_SYS_TIME 1 +#define VERSION "1.27" +#define GPGRT_ENABLE_ES_MACROS 1 +#define USE_POSIX_THREADS 1 diff --git a/repos/ports/ports/gnupg.hash b/repos/ports/ports/gnupg.hash new file mode 100644 index 0000000000..b7bffc2b86 --- /dev/null +++ b/repos/ports/ports/gnupg.hash @@ -0,0 +1 @@ +8ce83fbaac6f49a07708219ec64a9a0ae12606c4 diff --git a/repos/ports/ports/gnupg.port b/repos/ports/ports/gnupg.port new file mode 100644 index 0000000000..5c89094c94 --- /dev/null +++ b/repos/ports/ports/gnupg.port @@ -0,0 +1,7 @@ +LICENSE := GPLv3 +VERSION := 2.2.4 +DOWNLOADS := gnupg.archive + +URL(gnupg) := https://www.gnupg.org/ftp/gcrypt/gnupg/gnupg-$(VERSION).tar.bz2 +SHA(gnupg) := 732266e8888c6f41c084d043c7a0058332ff3580 +DIR(gnupg) := src/app/gnupg diff --git a/repos/ports/recipes/src/verify/content.mk b/repos/ports/recipes/src/verify/content.mk new file mode 100644 index 0000000000..fa2bd3405f --- /dev/null +++ b/repos/ports/recipes/src/verify/content.mk @@ -0,0 +1,14 @@ +content: src/app/verify src/app/gnupg LICENSE + +GNUPG_SRC_DIR := $(call port_dir,$(REP_DIR)/ports/gnupg)/src/app/gnupg + +src/app/verify: + $(mirror_from_rep_dir) + +src/app/gnupg: + mkdir -p $@ + cp -r $(addprefix $(GNUPG_SRC_DIR)/,g10 common kbx) $@ + +LICENSE: + cp $(GNUPG_SRC_DIR)/COPYING $@ + diff --git a/repos/ports/recipes/src/verify/hash b/repos/ports/recipes/src/verify/hash new file mode 100644 index 0000000000..52ad4476f3 --- /dev/null +++ b/repos/ports/recipes/src/verify/hash @@ -0,0 +1 @@ +2018-01-11 a131bb0a9eb207d83c2ffbd63cd4cab42b7b2ce1 diff --git a/repos/ports/recipes/src/verify/used_apis b/repos/ports/recipes/src/verify/used_apis new file mode 100644 index 0000000000..0c4ad461cb --- /dev/null +++ b/repos/ports/recipes/src/verify/used_apis @@ -0,0 +1,7 @@ +base +os +vfs +libc +timer_session +report_session +libgcrypt diff --git a/repos/ports/run/verify.run b/repos/ports/run/verify.run new file mode 100644 index 0000000000..f8043af33f --- /dev/null +++ b/repos/ports/run/verify.run @@ -0,0 +1,66 @@ +create_boot_directory + +import_from_depot genodelabs/src/[base_src] \ + genodelabs/src/init \ + genodelabs/src/report_rom \ + genodelabs/src/libc + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +build { app/verify } + +exec tar cf [run_dir]/genode/test.tar -C [genode_dir]/repos/ports/src/app/verify/test . + +file copy [genode_dir]/depot/nfeske/pubkey [run_dir]/genode/pubkey + +build_boot_image { verify libc.lib.so pthread.lib.so } + +append qemu_args " -nographic " + +run_genode_until {.*\n} 30 + +grep_output {\[init \-\> report_rom\]} + +compare_output_to { +[init -> report_rom] report 'verify -> result' +[init -> report_rom] +[init -> report_rom] +[init -> report_rom] +[init -> report_rom] +[init -> report_rom] +[init -> report_rom] +} diff --git a/repos/ports/src/app/verify/README b/repos/ports/src/app/verify/README new file mode 100644 index 0000000000..a6cef2b48c --- /dev/null +++ b/repos/ports/src/app/verify/README @@ -0,0 +1,19 @@ +The 'verify' component verifies detached OpenPGP signatures. Its configuration +accepts any number of '' nodes of the following form: + +! + +The detached signature file is expected to be named after the data file with +the additional suffix '.sig'. The 'path' and 'pubkey' attributes refer to +paths within the component's local VFS. + +The results of the signature checks are provided in the form of a report +with the label "result". For each '' node of the configuration, this +report contains a node of type '' or ''. In either case, the node +contains the corresponding 'path' as attribute. Furthermore, '' nodes +feature diagnostic information as a 'reason' attribute. + +For an example scenario, refer to the _ports/run/verify.run_ script. + +Disclaimer: The component does not perform time-related plausibility checks +such as scrutinizing the creation date of the public key. diff --git a/repos/ports/src/app/verify/assuan.h b/repos/ports/src/app/verify/assuan.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/repos/ports/src/app/verify/config.h b/repos/ports/src/app/verify/config.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/repos/ports/src/app/verify/dummies.c b/repos/ports/src/app/verify/dummies.c new file mode 100644 index 0000000000..80f720a056 --- /dev/null +++ b/repos/ports/src/app/verify/dummies.c @@ -0,0 +1,120 @@ +/* + * \brief Dummies needed to link the parts of GnuPG that we need + * \author Norman Feske + * \date 2018-01-06 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* libc includes */ +#include /* isascii, needed by gnupg headers */ + +/* GnuPG headers */ +#include +#include + + +/******************** + ** Silent dummies ** + ********************/ + +int check_special_filename(char const *fname, int for_write, int notranslate) +{ + return -1; +} + +void show_notation(PKT_signature *sig,int indent,int mode,int which) { } +void show_keyserver_url(PKT_signature *sig,int indent,int mode) { } +void show_policy_url(PKT_signature *sig,int indent,int mode) { } +void register_mem_cleanup_func() { } +int check_signatures_trust(ctrl_t ctrl, PKT_signature *sig) { return 0; } + +const char *asctimestamp(u32 stamp) { return ""; } + +u32 make_timestamp() { return ~0; /* disarm key-creation time check */ } + + +/*********************************************************** + ** Dummies that print a message when unexpectedly called ** + ***********************************************************/ + +#define DUMMY(ret_type, ret_val, name, args) \ +ret_type name args \ +{ \ + printf("%s: not implemented\n", __func__); \ + return ret_val; \ +} + +#define DUMMY_NORETURN(name, args) \ +void name args \ +{ \ + printf("%s: not implemented\n", __func__); \ + for (;;); \ +} + +DUMMY(byte const *, NULL, get_session_marker, (size_t *rlen)); +DUMMY(char const *, NULL, print_fname_stdin, (char const *s)); + +DUMMY_NORETURN(g10_exit, (int code)); + + +/* + * The following dummies are solely needed by mainproc.c + */ + +DUMMY(char *, NULL, bin2hex, (const void *buffer, size_t length, char *stringbuf)); +DUMMY(int, 0, decrypt_data, (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek)); +DUMMY(void, , dump_attribs, (const PKT_user_id *uid, PKT_public_key *pk)); +DUMMY(void, , free_keyserver_spec, ()); +DUMMY(void, , free_notation, (struct notation *notation)); +DUMMY(char *, NULL, get_matching_datafile, (const char *sigfilename)); +DUMMY(gpg_error_t, 0, get_override_session_key, (DEK *dek, const char *string)); +DUMMY(void, , get_ownertrust_info, ()); +DUMMY(gpg_error_t, 0, get_session_key, (ctrl_t ctrl, PKT_pubkey_enc *k, DEK *dek)); +DUMMY(char*, NULL, get_user_id, (ctrl_t ctrl, u32 *keyid, size_t *rn)); +DUMMY(char*, NULL, get_user_id_native, (ctrl_t ctrl, u32 *keyid)); +DUMMY(void, , get_validity, ()); +DUMMY(void, , get_validity_info, ()); +DUMMY(void, , gpg_dirmngr_get_pka, ()); +DUMMY(int, 0, handle_compressed, (ctrl_t ctrl, void *ctx, PKT_compressed *cd, int (*callback)(iobuf_t, void *), void *passthru)); +DUMMY(int, 0, have_secret_key_with_kid, (u32 *keyid)); +DUMMY(void, , is_valid_mailbox, ()); +DUMMY(void, , keyserver_any_configured, ()); +DUMMY(void, , keyserver_import_fprint, ()); +DUMMY(void, , keyserver_import_keyid, ()); +DUMMY(void, , keyserver_import_wkd, ()); +DUMMY(void, , merge_keys_and_selfsig, (ctrl_t ctrl, kbnode_t keyblock)); +DUMMY(void, , parse_keyserver_uri, ()); +DUMMY(void, , parse_preferred_keyserver, ()); +DUMMY(void, , passphrase_clear_cache, (const char *cacheid)); +DUMMY(DEK *, NULL, passphrase_to_dek, (int cipher_algo, STRING2KEY *s2k, int create, int nocache, const char *tryagain_text, int *canceled)); +DUMMY(void, , print_fingerprint, (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int mode)); +DUMMY(void, , print_key_line, (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret)); +DUMMY(void, , print_utf8_buffer, (estream_t fp, const void *p, size_t n)); +DUMMY(void, , show_photos, ()); +DUMMY(struct notation *, NULL, sig_to_notation, (PKT_signature *sig)); +DUMMY(const char *, NULL, strtimestamp, (u32 stamp)); +DUMMY(void, , trust_value_to_string, ()); +DUMMY(char *, NULL, utf8_to_native, (const char *string, size_t length, int delim)); +DUMMY(int, 0, get_pubkey_byfprint, (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock, const byte *fprint, size_t fprint_len)); +DUMMY(const char *, NULL, strtimevalue, (u32 stamp)); +DUMMY(char *, NULL, try_make_printable_string, (const void *p, size_t n, int delim)); +DUMMY(void, , zb32_encode, ()); +DUMMY(void, , image_type_to_string, ()); +DUMMY(int, 0, get_pubkey_fast, (PKT_public_key *pk, u32 *keyid)); +DUMMY(void, , parse_image_header, ()); +DUMMY(char *, NULL, make_outfile_name, (const char *iname)); +DUMMY(char *, NULL, ask_outfile_name, (const char *name, size_t namelen)); +DUMMY(int, 0, overwrite_filep, (const char *fname)); +DUMMY(void, , tty_get, ()); +DUMMY(void, , display_online_help, (const char *keyword)); +DUMMY(void, , tty_kill_prompt, ()); +DUMMY(int, 0, text_filter, (void *opaque, int control, iobuf_t chain, byte *buf, size_t *ret_len)); +DUMMY(iobuf_t, NULL, open_sigfile, (const char *sigfilename, progress_filter_context_t *pfx)); +DUMMY(void, , tty_printf, ()); +DUMMY(char *, NULL, gnupg_getcwd, ()); diff --git a/repos/ports/src/app/verify/gnupg.c b/repos/ports/src/app/verify/gnupg.c new file mode 100644 index 0000000000..84fecc9e8c --- /dev/null +++ b/repos/ports/src/app/verify/gnupg.c @@ -0,0 +1,151 @@ +/* + * \brief Wrapper for safely calling into GnuPG from C++ code + * \author Norman Feske + * \date 2018-01-06 + * + * We cannot directly include GnuPG's 'main.h' from C++ code. E.g., because + * the header uses C++ keywords as variable names. By using this wrapper, + * we keep C++ and C nicely separated. + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* local includes */ +#include "gnupg.h" + +/* libc includes */ +#include /* isascii, needed by gnupg headers */ + +/* GnuPG headers */ +#include +#include +#include + + +/* + * Global variable that is incremented by GnuPG whenever a signature check + * failed. + */ +int g10_errors_seen = 0; + + +enum Read_pubkey_result { READ_PUBKEY_OK, + READ_PUBKEY_MISSING_FILE, + READ_PUBKEY_INVALID_FORMAT }; + +/** + * Read public key into new packet + * + * The packet is allocated by this function and returned as 'packet_out_ptr' + * whenever it returns with 'READ_PUBKEY_OK'. + */ +static enum Read_pubkey_result +read_pubkey_from_file(char const *pubkey_path, PACKET **packet_out_ptr) +{ + *packet_out_ptr = NULL; + + /* set up parser context for parsing the public key data */ + struct parse_packet_ctx_s parse_ctx; + memset(&parse_ctx, 0, sizeof(parse_ctx)); + + parse_ctx.inp = iobuf_open(pubkey_path); + if (!parse_ctx.inp) + return READ_PUBKEY_MISSING_FILE; + + /* convert public key from ASCII-armored to binary representation */ + armor_filter_context_t *afx = new_armor_context (); + push_armor_filter(afx, parse_ctx.inp); + + /* parse public key data */ + PACKET * const packet = xmalloc(sizeof(*packet)); + memset(packet, 0, sizeof(*packet)); + int const parse_ok = (parse_packet(&parse_ctx, packet) == 0); + + release_armor_context(afx); + iobuf_close(parse_ctx.inp); + + if (parse_ok && packet->pkt.public_key) { + *packet_out_ptr = packet; + return READ_PUBKEY_OK; + } + + xfree(packet); + return READ_PUBKEY_INVALID_FORMAT; +} + + +/* + * Emulation of a key ring with only one public key. + */ +static PACKET *_pubkey_packet; + + + +/******************************************** + ** Implementation of the public interface ** + ********************************************/ + +enum Gnupg_verify_result gnupg_verify_detached_signature(char const *pubkey_path, + char const *data_path, + char const *sig_path) +{ + /* + * Obtain pointer to public-key packet. The packet is allocated by + * 'read_pubkey_from_file' and freed by 'verify_signatures'. + */ + switch (read_pubkey_from_file(pubkey_path, &_pubkey_packet)) { + case READ_PUBKEY_OK: break; + case READ_PUBKEY_MISSING_FILE: return GNUPG_VERIFY_PUBKEY_UNAVAILABLE; + case READ_PUBKEY_INVALID_FORMAT: return GNUPG_VERIFY_PUBKEY_INVALID; + }; + + /* + * Set up the GnuPG control context, which is normally the job of + * 'gpg_init_default_ctrl'. + */ + struct server_control_s control; + memset(&control, 0, sizeof(control)); + ctrl_t ctrl = &control; + ctrl->magic = SERVER_CONTROL_MAGIC; + + opt.quiet = 1; /* prevent disclaimer about key compliance */ + + /* + * Remember 'g10_errors_seen' before calling into GnuPG to obtain the + * feedback about the success of the signature verification. + */ + int const orig_errors_seen = g10_errors_seen; + + /* + * Call into GnuPG to verify the data with a detached signature. The + * 'verify_signatures' function indirectly calls 'get_pubkey' and + * 'get_pubkeyblock', which hand out our '_pubkey_packet'. + */ + char *file_names[2] = { strdup(sig_path), strdup(data_path) }; + verify_signatures(ctrl, 2, file_names); + for (unsigned i = 0; i < 2; i++) + free(file_names[i]); + + return (orig_errors_seen == g10_errors_seen) ? GNUPG_VERIFY_OK + : GNUPG_VERIFY_SIGNATURE_INVALID; +} + + +int get_pubkey(ctrl_t ctrl, PKT_public_key *pk, u32 *keyid) +{ + copy_public_key(pk, _pubkey_packet->pkt.public_key); + pk->flags.valid = 1; + return 0; +} + + +kbnode_t get_pubkeyblock(ctrl_t ctrl, u32 *keyid) +{ + return new_kbnode(_pubkey_packet); +} + diff --git a/repos/ports/src/app/verify/gnupg.h b/repos/ports/src/app/verify/gnupg.h new file mode 100644 index 0000000000..3b35cf982f --- /dev/null +++ b/repos/ports/src/app/verify/gnupg.h @@ -0,0 +1,33 @@ +/* + * \brief Interface used for invoking GnuPG code + * \author Norman Feske + * \date 2018-01-06 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _GNUPG_H_ +#define _GNUPG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum Gnupg_verify_result { GNUPG_VERIFY_OK, + GNUPG_VERIFY_PUBKEY_UNAVAILABLE, + GNUPG_VERIFY_PUBKEY_INVALID, + GNUPG_VERIFY_SIGNATURE_INVALID }; + +enum Gnupg_verify_result gnupg_verify_detached_signature(char const *pubkey_path, + char const *data_path, + char const *sig_path); +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* _GNUPG_H_ */ diff --git a/repos/ports/src/app/verify/main.cc b/repos/ports/src/app/verify/main.cc new file mode 100644 index 0000000000..3f26e2b2e5 --- /dev/null +++ b/repos/ports/src/app/verify/main.cc @@ -0,0 +1,104 @@ +/* + * \brief Tool for verifying detached signatures + * \author Norman Feske + * \date 2018-01-05 + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include + +/* local includes */ +#include + +namespace Verify { + using namespace Genode; + struct Main; +} + + +struct Verify::Main +{ + Env &_env; + + Attached_rom_dataspace _config { _env, "config" }; + + bool _verbose = false; + + Constructible _reporter { }; + + typedef String<256> Path; + typedef String<64> Message; + + static Message _message(Gnupg_verify_result result) + { + switch(result) { + case GNUPG_VERIFY_OK: return Message("good signature"); + case GNUPG_VERIFY_PUBKEY_UNAVAILABLE: return Message("public key unavailable"); + case GNUPG_VERIFY_PUBKEY_INVALID: return Message("malformed public key"); + case GNUPG_VERIFY_SIGNATURE_INVALID: return Message("bad signature"); + }; + return Message(); + } + + void _process_verify_node(Xml_node, Xml_generator &); + void _handle_config_with_libc(); + void _handle_config() { Libc::with_libc([&] () { _handle_config_with_libc(); }); } + + Signal_handler
_config_handler { _env.ep(), *this, &Main::_handle_config }; + + Main(Env &env) : _env(env) + { + _config.sigh(_config_handler); + _handle_config(); + } +}; + + +void Verify::Main::_process_verify_node(Xml_node node, Xml_generator &xml) +{ + Path const data_path = node.attribute_value("path", Path()); + Path const pubkey_path = node.attribute_value("pubkey", Path()); + + Gnupg_verify_result const result = + gnupg_verify_detached_signature(pubkey_path.string(), + data_path.string(), + Path(data_path, ".sig").string()); + if (_verbose) + log(data_path, ": ", _message(result)); + + bool const success = (result == GNUPG_VERIFY_OK); + xml.node(success ? "good" : "bad", [&] () { + xml.attribute("path", data_path); + if (!success) + xml.attribute("reason", _message(result)); + }); +} + + +void Verify::Main::_handle_config_with_libc() +{ + Xml_node const config = _config.xml(); + + _verbose = _config.xml().attribute_value("verbose", false); + + if (!_reporter.constructed()) { + _reporter.construct(_env, "result"); + _reporter->enabled(true); + } + + Reporter::Xml_generator xml(*_reporter, [&] () { + config.for_each_sub_node("verify", [&] (Xml_node node) { + _process_verify_node(node, xml); }); }); +} + + +void Libc::Component::construct(Libc::Env &env) { static Verify::Main main(env); } diff --git a/repos/ports/src/app/verify/target.mk b/repos/ports/src/app/verify/target.mk new file mode 100644 index 0000000000..fb16f2bb9e --- /dev/null +++ b/repos/ports/src/app/verify/target.mk @@ -0,0 +1,38 @@ +TARGET = verify +SRC_CC = main.cc +LIBS = base libc pthread libgcrypt + +GNUPG_SRC_DIR := $(call select_from_ports,gnupg)/src/app/gnupg/g10 + +INC_DIR += $(PRG_DIR) $(GNUPG_SRC_DIR) + +SRC_C := gnupg.c dummies.c + +# source codes from GnuPG +SRC_C += verify.c armor.c iobuf.c stringhelp.c progress.c strlist.c \ + cpr.c status.c mainproc.c sig-check.c keyid.c kbnode.c parse-packet.c \ + misc.c logging.c compliance.c free-packet.c mdfilter.c plaintext.c \ + seskey.c pkglue.c openpgp-oid.c + +CC_OPT += -DGPGRT_ENABLE_ES_MACROS \ + -DHAVE_ISASCII \ + -DHAVE_FSEEKO \ + -DHAVE_SIGNAL_H \ + -DGNUPG_NAME='"GnuPG"' \ + -DPRINTABLE_OS_NAME='"Genode"' \ + -DVERSION='"$(< $(GNUPG_SRC_DIR)/../VERSION)"' \ + -DGPG_USE_RSA + +CC_OPT_armor += -Wno-pointer-sign +CC_OPT_iobuf += -Wno-pointer-sign +CC_OPT_stringhelp += -Wno-pointer-sign +CC_OPT_progress += -Wno-pointer-sign +CC_OPT_mainproc += -Wno-pointer-sign +CC_OPT_sig-check += -Wno-pointer-sign +CC_OPT_parse-packet += -Wno-pointer-sign +CC_OPT_misc += -DSCDAEMON_NAME='"scdaemon"' -DEXTSEP_S='"."' -DPATHSEP_S='";"' + +vpath gnupg.c $(PRG_DIR) +vpath dummies.c $(PRG_DIR) +vpath %.c $(GNUPG_SRC_DIR) +vpath %.c $(GNUPG_SRC_DIR)/../common diff --git a/repos/ports/src/app/verify/test/expect_invalid.txt b/repos/ports/src/app/verify/test/expect_invalid.txt new file mode 100644 index 0000000000..24b9e6b168 --- /dev/null +++ b/repos/ports/src/app/verify/test/expect_invalid.txt @@ -0,0 +1 @@ +Streifenhoernchen sind lecker diff --git a/repos/ports/src/app/verify/test/expect_invalid.txt.sig b/repos/ports/src/app/verify/test/expect_invalid.txt.sig new file mode 100644 index 0000000000..f0d6ec73c0 Binary files /dev/null and b/repos/ports/src/app/verify/test/expect_invalid.txt.sig differ diff --git a/repos/ports/src/app/verify/test/expect_valid.txt b/repos/ports/src/app/verify/test/expect_valid.txt new file mode 100644 index 0000000000..b706a38ee4 --- /dev/null +++ b/repos/ports/src/app/verify/test/expect_valid.txt @@ -0,0 +1 @@ +Kinder moegen Suessigkeiten diff --git a/repos/ports/src/app/verify/test/expect_valid.txt.sig b/repos/ports/src/app/verify/test/expect_valid.txt.sig new file mode 100644 index 0000000000..f9f604651d Binary files /dev/null and b/repos/ports/src/app/verify/test/expect_valid.txt.sig differ