Signature checking tool based on GnuPG

The new 'verify' component facilitates the code of GnuPG to verify
detached OpenPGP signatures against public keys.

Since GnuPG depends on libgcrypt and libgpg-error, the patch adds these
libraries to the libports repository.

Fixes #2640
This commit is contained in:
Norman Feske 2018-01-05 20:02:16 +01:00
parent 8fca8a9a04
commit 5b6bd8459f
30 changed files with 838 additions and 0 deletions

View File

@ -0,0 +1 @@
INC_DIR += $(call select_from_ports,libgcrypt)/include/libgcrypt

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1 @@
c9c155548be98de2f3fcf27400838caaee3db765

View File

@ -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 <sys\/select.h>" \
"@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 > $@

View File

@ -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 $@

View File

@ -0,0 +1 @@
2018-01-11 5d8f799b6f0c03d4d1697da40c858d878b2e3664

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
static char mod_source_info[] = "";

View File

@ -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/<architecture>/'.
*/
#include <../mpi/generic/mpi-asm-defs.h>

View File

@ -0,0 +1,32 @@
#define BUILD_REVISION "0"
#define BUILD_TIMESTAMP "<none>"
#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

View File

@ -0,0 +1 @@
8ce83fbaac6f49a07708219ec64a9a0ae12606c4

View File

@ -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

View File

@ -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 $@

View File

@ -0,0 +1 @@
2018-01-11 a131bb0a9eb207d83c2ffbd63cd4cab42b7b2ce1

View File

@ -0,0 +1,7 @@
base
os
vfs
libc
timer_session
report_session
libgcrypt

View File

@ -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 {
<config>
<parent-provides>
<service name="CPU"/>
<service name="LOG"/>
<service name="PD"/>
<service name="RAM"/>
<service name="ROM"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<start name="report_rom" caps="100">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="yes"/>
</start>
<start name="verify" caps="200">
<resource name="RAM" quantum="12M"/>
<config verbose="yes">
<libc stdout="/dev/log" stderr="/dev/null" rtc="/dev/null"/>
<vfs>
<rom name="pubkey"/>
<tar name="test.tar"/>
<dir name="dev"> <log/> <null/> </dir>
</vfs>
<verify path="expect_valid.txt" pubkey="/nonexistent_pubkey"/>
<verify path="expect_valid.txt" pubkey="/dev/null"/>
<verify path="expect_valid.txt" pubkey="/pubkey"/>
<verify path="expect_invalid.txt" pubkey="/pubkey"/>
</config>
</start>
</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 {</result>.*\n} 30
grep_output {\[init \-\> report_rom\]}
compare_output_to {
[init -> report_rom] report 'verify -> result'
[init -> report_rom] <result>
[init -> report_rom] <bad path="expect_valid.txt" reason="public key unavailable"/>
[init -> report_rom] <bad path="expect_valid.txt" reason="malformed public key"/>
[init -> report_rom] <good path="expect_valid.txt"/>
[init -> report_rom] <bad path="expect_invalid.txt" reason="bad signature"/>
[init -> report_rom] </result>
}

View File

@ -0,0 +1,19 @@
The 'verify' component verifies detached OpenPGP signatures. Its configuration
accepts any number of '<verify>' nodes of the following form:
! <verify path="/path/to/data" pubkey="/pubkey"/>
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 '<verify>' node of the configuration, this
report contains a node of type '<good>' or '<bad>'. In either case, the node
contains the corresponding 'path' as attribute. Furthermore, '<bad>' 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.

View File

View File

View File

@ -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 <ctype.h> /* isascii, needed by gnupg headers */
/* GnuPG headers */
#include <gpg.h>
#include <main.h>
/********************
** 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 "<sometime>"; }
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, ());

View File

@ -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 <ctype.h> /* isascii, needed by gnupg headers */
/* GnuPG headers */
#include <gpg.h>
#include <main.h>
#include <options.h>
/*
* 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);
}

View File

@ -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_ */

View File

@ -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 <libc/component.h>
#include <base/attached_rom_dataspace.h>
#include <os/reporter.h>
/* local includes */
#include <gnupg.h>
namespace Verify {
using namespace Genode;
struct Main;
}
struct Verify::Main
{
Env &_env;
Attached_rom_dataspace _config { _env, "config" };
bool _verbose = false;
Constructible<Reporter> _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<Main> _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); }

View File

@ -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

View File

@ -0,0 +1 @@
Streifenhoernchen sind lecker

Binary file not shown.

View File

@ -0,0 +1 @@
Kinder moegen Suessigkeiten

Binary file not shown.