Merged in sync make-cleanup
authorKrista 'DarthMama' Bennett <krista@pep.foundation>
Wed, 23 Jan 2019 11:59:43 +0100
branchmake-cleanup
changeset 32357633eeee2cd4
parent 3208 204ff09a2787
parent 3234 538a03bab6b8
child 3236 efb3aff10882
Merged in sync
src/Makefile
test/Makefile
     1.1 --- a/.hgtags	Mon Dec 24 15:32:27 2018 +0100
     1.2 +++ b/.hgtags	Wed Jan 23 11:59:43 2019 +0100
     1.3 @@ -9,3 +9,4 @@
     1.4  e4d80dd0a663c5397a6a9178e08aea1e7808d43e Patch release 1.0.442
     1.5  43ab5608555e12cb110ccda79cbfb9783e40408b Release 1.1.0
     1.6  084c00652ac9fedcd56e2c316be795ed0ba00b2f Release 1.1.1
     1.7 +eace10725457069b5c5bfdb8723e876bfa63d753 Release 1.2.0
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/default.conf	Wed Jan 23 11:59:43 2019 +0100
     2.3 @@ -0,0 +1,280 @@
     2.4 +# Copyright 2017, pEp Foundation
     2.5 +# This file is part of pEpEngine
     2.6 +# This file may be used under the terms of the GNU General Public License version 3
     2.7 +# see LICENSE.txt
     2.8 +
     2.9 +# See `doc/build-<your platform>.md` for documentation on how to build, and customize your build.
    2.10 +
    2.11 +# This file sets all the make variables that allow you to customize a build.
    2.12 +# There are 4 ways in which you can customize your build:
    2.13 +# 1) Edit the variable assignments in this file (this is a tracked file, so your repository will be dirty)
    2.14 +# 2) Edit the variable assignments in `Makefile.conf` (which is a tracked file, so your repository will be dirty)
    2.15 +# 3) Create `local.conf` and fill it with variable assignments.
    2.16 +# 4) Set the environment variable `BUILD_CONFIG` to an absolute path.
    2.17 +#    The variable assignments found in the make file at the path indicated by `BUILD_CONFIG` will be evaluated.
    2.18 +# Customization options are applied in the order given above. Later variable assignments take precedence over earlier ones.
    2.19 +# It is possible to use multiple variants simultaniously.
    2.20 +# If nothing is changed according to these 4 methods, a default configuration for your platform (specified below) will be used for the build.
    2.21 +
    2.22 +
    2.23 +######### Header #########
    2.24 +HERE:=$(dir $(lastword $(MAKEFILE_LIST)))
    2.25 +
    2.26 +
    2.27 +######### General #########
    2.28 +# To use (only) system libraries, set all the *_INC and *_LIB variables to the empty string.
    2.29 +# All the *_INC and *_LIB variables are command line flags, not paths.
    2.30 +# Thus, all *_INC variables' values must start with "-I", and all *_LIB variables' values must start with "-L".
    2.31 +
    2.32 +BUILD_ON:=$(shell uname)
    2.33 +
    2.34 +# This variable specifies the platform that the engine should be cross-compiled for.
    2.35 +BUILD_FOR=$(BUILD_ON)
    2.36 +
    2.37 +# Cross-compiling is currently not supported.
    2.38 +# Maybe you can hack something with `local.conf`.
    2.39 +ifneq ($(BUILD_ON),$(BUILD_FOR))
    2.40 +    $(error I don't know how to build for $(BUILD_FOR) on $(BUILD_ON).)
    2.41 +endif
    2.42 +
    2.43 +# Installation path prefix for libraries and binaries, except for system.db
    2.44 +PREFIX=$(HOME)
    2.45 +
    2.46 +# Installation path for system.db
    2.47 +SYSTEM_DB=/usr/local/share/pEp/system.db
    2.48 +
    2.49 +# Filename of the pEpEngine library
    2.50 +ifeq ($(BUILD_FOR),Linux)
    2.51 +    TARGET=libpEpEngine.so
    2.52 +else ifeq ($(BUILD_FOR),Darwin)
    2.53 +    TARGET=libpEpEngine.dylib
    2.54 +endif
    2.55 +
    2.56 +# If empty, create a release build.
    2.57 +# Otherwise, create a debug build.
    2.58 +# This variable is ineffective in your local.conf file.
    2.59 +DEBUG=placeholder
    2.60 +
    2.61 +# If empty, suppress compiler warnings.
    2.62 +# Otherwise, print warnings.
    2.63 +# This variable is ineffective in your local.conf file.
    2.64 +WARN=placeholder
    2.65 +
    2.66 +
    2.67 +######### C and C++ #########
    2.68 +TARGET_ARCH=
    2.69 +# The following two variables will be appended to.
    2.70 +# You can thus not set them to a fixed value here.
    2.71 +ifeq ($(BUILD_FOR),Linux)
    2.72 +    LDFLAGS=
    2.73 +else ifeq ($(BUILD_FOR),Darwin)
    2.74 +    # "-bind_at_load" helps find symbol resolution errors faster
    2.75 +    LDFLAGS=-bind_at_load
    2.76 +endif
    2.77 +
    2.78 +LDLIBS=
    2.79 +
    2.80 +
    2.81 +######### C #########
    2.82 +ifeq ($(BUILD_FOR),Linux)
    2.83 +    CC=gcc -std=c99 -pthread
    2.84 +else ifeq ($(BUILD_FOR),Darwin)
    2.85 +    # clang issues a warning when "-pthread" is used for linking.
    2.86 +    # So, include it in CFLAGS, and not in CC
    2.87 +    CC=clang -std=c99
    2.88 +endif
    2.89 +
    2.90 +ifeq ($(BUILD_FOR),Linux)
    2.91 +    CFLAGS=-fPIC -fstrict-aliasing -fdiagnostics-color=always
    2.92 +else ifeq ($(BUILD_FOR),Darwin)
    2.93 +    CFLAGS=-pthread -fPIC -fstrict-aliasing -fcolor-diagnostics
    2.94 +endif
    2.95 +
    2.96 +CPPFLAGS=
    2.97 +
    2.98 +# The flag -DNDEBUG will always be removed from CFLAGS for compiling tests.
    2.99 +# The tests do not work properly, if compiled with -DNDEBUG
   2.100 +ifeq ($(BUILD_FOR),Linux)
   2.101 +    ifdef WARN
   2.102 +        CFLAGS+= -Wall -pedantic -Wstrict-aliasing=3
   2.103 +    else
   2.104 +        CFLAGS+= -w
   2.105 +    endif
   2.106 +    ifdef DEBUG
   2.107 +        CFLAGS+= -g -ggdb -DDEBUG_ERRORSTACK
   2.108 +    else
   2.109 +        CFLAGS+= -O3 -DNDEBUG
   2.110 +    endif
   2.111 +else ifeq ($(BUILD_FOR),Darwin)
   2.112 +    ifdef WARN
   2.113 +        # FIXME Remove 'no-extended-offsetof' after ENGINE-236 is closed.
   2.114 +        CFLAGS+= -Wall -pedantic -Wno-extended-offsetof
   2.115 +    else
   2.116 +        CFLAGS+= -w
   2.117 +    endif
   2.118 +    ifdef DEBUG
   2.119 +        CFLAGS+= -O0 -g -DDEBUG_ERRORSTACK
   2.120 +    else
   2.121 +        CFLAGS+= -O3 -DNDEBUG
   2.122 +    endif
   2.123 +endif
   2.124 +
   2.125 +# Additional CFLAGS used for compiling ASN1C-generated code
   2.126 +ifeq ($(BUILD_FOR),Linux)
   2.127 +    # The '_DEFAULT_SOURCE' feature test macro is required to suppress the warning
   2.128 +    #   _BSD_SOURCE and _SVID_SOURCE are deprecated, use _DEFAULT_SOURCE
   2.129 +    # otherwise printed during the compilation of every asn1c-generated C file.
   2.130 +    # It's a glibc specific warning, only present in few versions around ~2.19.
   2.131 +    # See https://lwn.net/Articles/590381/ for a discussion.
   2.132 +    CFLAGS_GENERATED=-D_DEFAULT_SOURCE
   2.133 +else ifeq ($(BUILD_FOR),Darwin)
   2.134 +    CFLAGS_GENERATED=
   2.135 +endif
   2.136 +
   2.137 +
   2.138 +######### C++ #########
   2.139 +ifeq ($(BUILD_FOR),Linux)
   2.140 +    CXX=g++ -std=gnu++11 -pthread
   2.141 +else ifeq ($(BUILD_FOR),Darwin)
   2.142 +    # clang issues a warning when "-pthread" is used for linking. So, include it in CXXFLAGS, and not in CXX
   2.143 +    CXX=clang -std=c++11
   2.144 +endif
   2.145 +
   2.146 +# The flag -DNDEBUG will always be removed from CXXFLAGS for compiling tests.
   2.147 +# The tests do not work properly, if compiled with -DNDEBUG
   2.148 +ifeq ($(BUILD_FOR),Linux)
   2.149 +    CXXFLAGS=-fdiagnostics-color=always -I../src -I../asn.1 $(ETPAN_INC)
   2.150 +    ifdef WARN
   2.151 +        CXXFLAGS+=
   2.152 +    else
   2.153 +        CXXFLAGS+= -w
   2.154 +    endif
   2.155 +    ifdef DEBUG
   2.156 +        CXXFLAGS+= -g -ggdb
   2.157 +    else
   2.158 +        CXXFLAGS+= -O3 -DNDEBUG
   2.159 +    endif
   2.160 +else ifeq ($(BUILD_FOR),Darwin)
   2.161 +    CXXFLAGS=-pthread -fcolor-diagnostics -I../src -I../asn.1 $(ETPAN_INC)
   2.162 +    ifdef WARN
   2.163 +        CXXFLAGS+=
   2.164 +    else
   2.165 +        CXXFLAGS+= -w
   2.166 +    endif
   2.167 +    ifdef DEBUG
   2.168 +        CXXFLAGS+= -O0 -g
   2.169 +    else
   2.170 +        CXXFLAGS+= -O3 -DNDEBUG
   2.171 +    endif
   2.172 +endif
   2.173 +
   2.174 +
   2.175 +######### YML2 #########
   2.176 +YML2_PATH=$(HOME)/yml2
   2.177 +
   2.178 +YML2_PROC=$(YML2_PATH)/yml2proc
   2.179 +
   2.180 +YML2_OPTS=--encoding=utf8
   2.181 +
   2.182 +
   2.183 +######### asn1c #########
   2.184 +# asn1c binary
   2.185 +ASN1C=asn1c
   2.186 +
   2.187 +# asn1c include search flag
   2.188 +ASN1C_INC=-I$(PREFIX)/include
   2.189 +
   2.190 +
   2.191 +######### libetpan #########
   2.192 +# libetpan library search flag
   2.193 +ETPAN_LIB=-L$(PREFIX)/lib
   2.194 +
   2.195 +# libetpan include search flag
   2.196 +ETPAN_INC=-I$(PREFIX)/include
   2.197 +
   2.198 +
   2.199 +######### sqlite3 #########
   2.200 +# If empty (or undefined), compile sqlite3 from the sources shipped with the pEp distribution.
   2.201 +# Otherwise, use an sqlite3 implementation found in the OS's include/library paths.
   2.202 +SQLITE3_FROM_OS=placeholder
   2.203 +
   2.204 +
   2.205 +######### OpenPGP #########
   2.206 +# Path of GPG binary
   2.207 +# gpgconf is not available for old version of GPG, for example GPG 2.0.30. Override this variable, if you compile the engine for such an old version.
   2.208 +GPG_CMD:=$(shell gpgconf --list-components | awk -F: '/^gpg:/ { print $$3; exit 0; }')
   2.209 +
   2.210 +# Selects OpenPGP implementation. must be either `GPG` or `NETPGP` or `SEQUOIA`
   2.211 +OPENPGP=GPG
   2.212 +
   2.213 +# Path of libGPGME binary
   2.214 +ifeq ($(BUILD_FOR),Linux)
   2.215 +    LIBGPGME=libgpgme.so.11
   2.216 +else ifeq ($(BUILD_FOR),Darwin)
   2.217 +    LIBGPGME=libgpgme.11.dylib
   2.218 +endif
   2.219 +
   2.220 +# libGPGME library search flag
   2.221 +ifeq ($(BUILD_FOR),Linux)
   2.222 +    GPGME_LIB=
   2.223 +else ifeq ($(BUILD_FOR),Darwin)
   2.224 +    GPGME_LIB=-L$(HOME)/lib
   2.225 +endif
   2.226 +
   2.227 +# libGPGME include search flag
   2.228 +ifeq ($(BUILD_FOR),Linux)
   2.229 +    GPGME_INC=
   2.230 +else ifeq ($(BUILD_FOR),Darwin)
   2.231 +    GPGME_INC=-I$(HOME)/include
   2.232 +endif
   2.233 +
   2.234 +# NETPGP library search flag
   2.235 +NETPGP_LIB=
   2.236 +#NETPGP_LIB=-L$(PREFIX)/lib
   2.237 +
   2.238 +# libGPGME include search flag
   2.239 +NETPGP_INC=
   2.240 +#NETPGP_INC=-I$(PREFIX)/include
   2.241 +
   2.242 +SEQUOIA_CFLAGS=$(shell pkg-config --cflags-only-other sequoia)
   2.243 +SEQUOIA_LDFLAGS=$(shell pkg-config --libs-only-L --libs-only-other sequoia)
   2.244 +SEQUOIA_LIB=$(shell pkg-config --libs-only-l sequoia)
   2.245 +SEQUOIA_INC=$(shell pkg-config --cflags-only-I sequoia)
   2.246 +
   2.247 +
   2.248 +######### OpenPGP #########
   2.249 +# CppUnit library search flag
   2.250 +CPPUNIT_LIB=
   2.251 +#CPPUNIT_LIB=-L$(HOME)/local/lib
   2.252 +
   2.253 +# CppUnit include search flag
   2.254 +CPPUNIT_INC=
   2.255 +#CPPUNIT_INC=-I$(HOME)/local/inc
   2.256 +
   2.257 +
   2.258 +######### Engine internals #########
   2.259 +# C macros (not environment variables) that can be overridden:
   2.260 +# DEFAULT_KEYSERVER - string with default keyserver
   2.261 +# CRASHDUMP_DEFAULT_LINES - number of log lines to deliver for crashdumps
   2.262 +# Example:
   2.263 +#    EXTRA_MACROS=-DDEFAULT_KEYSERVER=\"default-server.org\" -DCRASHDUMP_DEFAULT_LINES=23
   2.264 +EXTRA_MACROS=
   2.265 +
   2.266 +
   2.267 +######### Misc #########
   2.268 +# FIXME Maybe include these variables here.
   2.269 +# Check how they are used throughout the project before setting them here
   2.270 +#LLDB_BIN
   2.271 +
   2.272 +
   2.273 +######### Footer #########
   2.274 +include $(HERE)/Makefile.conf
   2.275 +
   2.276 +-include $(HERE)/local.conf
   2.277 +
   2.278 +ifdef BUILD_CONFIG
   2.279 +    include $(BUILD_CONFIG)
   2.280 +endif
   2.281 +
   2.282 +# YML_PATH is needed in the environment of every call to a program of the YML2 distribution
   2.283 +export YML_PATH=$(YML2_PATH)
     3.1 --- a/src/Makefile	Mon Dec 24 15:32:27 2018 +0100
     3.2 +++ b/src/Makefile	Wed Jan 23 11:59:43 2019 +0100
     3.3 @@ -35,15 +35,20 @@
     3.4  endif
     3.5  
     3.6  ifeq ($(OPENPGP),GPG)
     3.7 -    NO_SOURCE+= pgp_netpgp.c
     3.8 +    NO_SOURCE+= pgp_netpgp.c pgp_sequoia.c
     3.9      CFLAGS+= -DUSE_GPG $(GPGME_INC) -DLIBGPGME=\"$(LIBGPGME)\"
    3.10      LDFLAGS+= $(GPGME_LIB)
    3.11      # No extra LDLIBS are needed here, because GPGME is dynamically loaded
    3.12  else ifeq ($(OPENPGP),NETPGP)
    3.13 -    NO_SOURCE+= pgp_gpg.c
    3.14 +    NO_SOURCE+= pgp_gpg.c pgp_sequoia.c
    3.15      CFLAGS+= -DUSE_NETPGP $(NETGPG_INC)
    3.16      LDFLAGS+= $(NETGPG_LIB)
    3.17      LDLIBS+= -lnetpgp -lcurl
    3.18 +else ifeq ($(OPENPGP),SEQUOIA)
    3.19 +    NO_SOURCE+= pgp_gpg.c pgp_netpgp.c
    3.20 +    CFLAGS+= -DUSE_SEQUOIA $(SEQUOIA_CFLAGS) $(SEQUOIA_INC)
    3.21 +    LDFLAGS+= $(SEQUOIA_LDFLAGS)
    3.22 +    LDLIBS+= $(SEQUOIA_LIB)
    3.23  else
    3.24      $(error Unknown OpenPGP library: $(OPENPGP))
    3.25  endif
     4.1 --- a/src/cryptotech.c	Mon Dec 24 15:32:27 2018 +0100
     4.2 +++ b/src/cryptotech.c	Wed Jan 23 11:59:43 2019 +0100
     4.3 @@ -8,6 +8,10 @@
     4.4  #else
     4.5  #ifdef USE_NETPGP
     4.6  #include "pgp_netpgp.h"
     4.7 +#else
     4.8 +#ifdef USE_SEQUOIA
     4.9 +#include "pgp_sequoia.h"
    4.10 +#endif
    4.11  #endif
    4.12  #endif
    4.13  // 
     5.1 --- a/src/keymanagement.c	Mon Dec 24 15:32:27 2018 +0100
     5.2 +++ b/src/keymanagement.c	Wed Jan 23 11:59:43 2019 +0100
     5.3 @@ -102,9 +102,14 @@
     5.4      return PEP_STATUS_OK;
     5.5  }
     5.6  
     5.7 +
     5.8 +// own_must_contain_private is usually true when calling;
     5.9 +// we only set it to false when we have the idea of
    5.10 +// possibly having an own pubkey that we need to check on its own
    5.11  static PEP_STATUS validate_fpr(PEP_SESSION session, 
    5.12                                 pEp_identity* ident,
    5.13 -                               bool check_blacklist) {
    5.14 +                               bool check_blacklist,
    5.15 +                               bool own_must_contain_private) {
    5.16      
    5.17      PEP_STATUS status = PEP_STATUS_OK;
    5.18      
    5.19 @@ -114,12 +119,14 @@
    5.20      char* fpr = ident->fpr;
    5.21      
    5.22      bool has_private = false;
    5.23 +    status = contains_priv_key(session, fpr, &has_private);
    5.24      
    5.25 -    if (ident->me) {
    5.26 -        status = contains_priv_key(session, fpr, &has_private);
    5.27 +    if (ident->me && own_must_contain_private) {
    5.28          if (status != PEP_STATUS_OK || !has_private)
    5.29              return PEP_KEY_UNSUITABLE;
    5.30      }
    5.31 +    else if (status != PEP_STATUS_OK && has_private) // should never happen
    5.32 +        has_private = false;
    5.33      
    5.34      status = get_trust(session, ident);
    5.35      if (status != PEP_STATUS_OK)
    5.36 @@ -195,7 +202,9 @@
    5.37          }
    5.38      }
    5.39              
    5.40 -    if (ident->me && (ct >= PEP_ct_strong_but_unconfirmed) && !revoked && expired) {
    5.41 +    if (ident->me && has_private && 
    5.42 +        (ct >= PEP_ct_strong_but_unconfirmed) && 
    5.43 +        !revoked && expired) {
    5.44          // extend key
    5.45          timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
    5.46          status = renew_key(session, fpr, ts);
    5.47 @@ -351,7 +360,7 @@
    5.48      // Input: stored identity retrieved from database
    5.49      // if stored identity contains a default key
    5.50      if (!EMPTYSTR(stored_fpr)) {
    5.51 -        status = validate_fpr(session, stored_identity, check_blacklist);    
    5.52 +        status = validate_fpr(session, stored_identity, check_blacklist, true);    
    5.53          if (status == PEP_STATUS_OK && !EMPTYSTR(stored_identity->fpr)) {
    5.54              *is_identity_default = *is_address_default = true;
    5.55              return status;
    5.56 @@ -371,7 +380,7 @@
    5.57      if (!EMPTYSTR(user_fpr)) {             
    5.58          // There exists a default key for user, so validate
    5.59          stored_identity->fpr = user_fpr;
    5.60 -        status = validate_fpr(session, stored_identity, check_blacklist);
    5.61 +        status = validate_fpr(session, stored_identity, check_blacklist, true);
    5.62          if (status == PEP_STATUS_OK && stored_identity->fpr) {
    5.63              *is_user_default = true;
    5.64              *is_address_default = key_matches_address(session, 
    5.65 @@ -388,7 +397,7 @@
    5.66      status = elect_pubkey(session, stored_identity, check_blacklist);
    5.67      if (status == PEP_STATUS_OK) {
    5.68          if (!EMPTYSTR(stored_identity->fpr))
    5.69 -            validate_fpr(session, stored_identity, false); // blacklist already filtered of needed
    5.70 +            validate_fpr(session, stored_identity, false, true); // blacklist already filtered of needed
    5.71      }    
    5.72      else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
    5.73          first_reject_status = status;
    5.74 @@ -1072,7 +1081,7 @@
    5.75      // check stored identity
    5.76      if (stored_identity && !EMPTYSTR(stored_identity->fpr)) {
    5.77          // Fall back / retrieve
    5.78 -        status = validate_fpr(session, stored_identity, false);
    5.79 +        status = validate_fpr(session, stored_identity, false, true);
    5.80          if (status == PEP_OUT_OF_MEMORY)
    5.81              goto pEp_free;
    5.82          if (status == PEP_STATUS_OK) {
    5.83 @@ -1140,9 +1149,13 @@
    5.84          identity->comm_type = PEP_ct_unknown;
    5.85      }
    5.86      
    5.87 -    status = set_identity(session, identity);
    5.88 -    if (status == PEP_STATUS_OK)
    5.89 -        status = set_as_pEp_user(session, identity);
    5.90 +    // We want to set an identity in the DB even if a key isn't found, but we have to preserve the status if
    5.91 +    // it's NOT ok
    5.92 +    PEP_STATUS set_id_status = set_identity(session, identity);
    5.93 +    if (set_id_status == PEP_STATUS_OK)
    5.94 +        set_id_status = set_as_pEp_user(session, identity);
    5.95 +
    5.96 +    status = (status == PEP_STATUS_OK ? set_id_status : status);
    5.97  
    5.98  pEp_free:    
    5.99      free(default_own_id);
   5.100 @@ -1377,7 +1390,9 @@
   5.101              EMPTYSTR(ident->fpr))
   5.102          return PEP_ILLEGAL_VALUE;
   5.103  
   5.104 -    //bool ident_has_trusted_default = false;
   5.105 +    if (is_me(session, ident))
   5.106 +        return PEP_ILLEGAL_VALUE;
   5.107 +        
   5.108      char* ident_default_fpr = NULL;
   5.109  
   5.110      // Before we do anything, be sure the input fpr is even eligible to be trusted
   5.111 @@ -1390,8 +1405,6 @@
   5.112      if (status != PEP_STATUS_OK)
   5.113          return status;
   5.114  
   5.115 -    bool me = is_me(session, ident);
   5.116 -
   5.117      pEp_identity* ident_copy = identity_dup(ident);
   5.118      char* cached_fpr = NULL;
   5.119  
   5.120 @@ -1400,31 +1413,14 @@
   5.121  
   5.122      // For later, in case we need to check the user default key
   5.123      pEp_identity* tmp_user_ident = NULL;
   5.124 -
   5.125 -    if (me) {
   5.126 -        bool has_private = false;
   5.127 -        // first of all, does this key even have a private component.
   5.128 -        status = contains_priv_key(session, ident->fpr, &has_private);
   5.129 -        if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
   5.130 -            goto pEp_free;
   5.131 -            
   5.132 -        // if (has_private) {
   5.133 -        //     status = set_own_key(session, ident_copy, ident->fpr); 
   5.134 -        //     goto pEp_free;
   5.135 -        // }
   5.136 -    }
   5.137 -    
   5.138 -    // Either it's not me, or it's me but the key has no private key. 
   5.139 -    // We're only talking about pub keys here. Moving on.
   5.140 -    
   5.141 +        
   5.142      // Save the input fpr, which we already tested as non-NULL
   5.143      cached_fpr = strdup(ident->fpr);
   5.144  
   5.145      // Set up a temp trusted identity for the input fpr without a comm type;
   5.146      tmp_id = new_identity(ident->address, ident->fpr, ident->user_id, NULL);
   5.147      
   5.148 -    // ->me isn't set, even if this is an own identity, so this will work.
   5.149 -    status = validate_fpr(session, tmp_id, false);
   5.150 +    status = validate_fpr(session, tmp_id, false, true);
   5.151          
   5.152      if (status == PEP_STATUS_OK) {
   5.153          // Validate fpr gets trust DB or, when that fails, key comm type. we checked
   5.154 @@ -1432,10 +1428,7 @@
   5.155          tmp_id->comm_type = _MAX(tmp_id->comm_type, input_default_ct) | PEP_ct_confirmed;
   5.156  
   5.157          // Get the default identity without setting the fpr                                       
   5.158 -        if (me)
   5.159 -            status = _myself(session, ident_copy, false, true);
   5.160 -        else    
   5.161 -            status = update_identity(session, ident_copy);
   5.162 +        status = update_identity(session, ident_copy);
   5.163              
   5.164          ident_default_fpr = (EMPTYSTR(ident_copy->fpr) ? NULL : strdup(ident_copy->fpr));
   5.165  
   5.166 @@ -1443,13 +1436,13 @@
   5.167              bool trusted_default = false;
   5.168  
   5.169              // If there's no default, or the default is different from the input...
   5.170 -            if (me || EMPTYSTR(ident_default_fpr) || strcmp(cached_fpr, ident_default_fpr) != 0) {
   5.171 +            if (EMPTYSTR(ident_default_fpr) || strcmp(cached_fpr, ident_default_fpr) != 0) {
   5.172                  
   5.173                  // If the default fpr (if there is one) is trusted and key is strong enough,
   5.174                  // don't replace, we just set the trusted bit on this key for this user_id...
   5.175                  // (If there's no default fpr, this won't be true anyway.)
   5.176 -                if (me || (ident_copy->comm_type >= PEP_ct_strong_but_unconfirmed && 
   5.177 -                          (ident_copy->comm_type & PEP_ct_confirmed))) {                        
   5.178 +                if ((ident_copy->comm_type >= PEP_ct_strong_but_unconfirmed && 
   5.179 +                    (ident_copy->comm_type & PEP_ct_confirmed))) {                        
   5.180  
   5.181                      trusted_default = true;
   5.182                                      
   5.183 @@ -1487,7 +1480,7 @@
   5.184                      if (!tmp_user_ident)
   5.185                          status = PEP_OUT_OF_MEMORY;
   5.186                      else {
   5.187 -                        status = validate_fpr(session, tmp_user_ident, false);
   5.188 +                        status = validate_fpr(session, tmp_user_ident, false, true);
   5.189                          
   5.190                          if (status != PEP_STATUS_OK ||
   5.191                              tmp_user_ident->comm_type < PEP_ct_strong_but_unconfirmed ||
   5.192 @@ -1511,6 +1504,45 @@
   5.193      return status;
   5.194  }
   5.195  
   5.196 +DYNAMIC_API PEP_STATUS trust_own_key(
   5.197 +        PEP_SESSION session,
   5.198 +        pEp_identity* ident
   5.199 +    ) 
   5.200 +{
   5.201 +    assert(session);
   5.202 +    assert(ident);
   5.203 +    assert(!EMPTYSTR(ident->address));
   5.204 +    assert(!EMPTYSTR(ident->user_id));
   5.205 +    assert(!EMPTYSTR(ident->fpr));
   5.206 +    
   5.207 +    if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
   5.208 +            EMPTYSTR(ident->fpr))
   5.209 +        return PEP_ILLEGAL_VALUE;
   5.210 +
   5.211 +    if (!is_me(session, ident))
   5.212 +        return PEP_ILLEGAL_VALUE;
   5.213 +
   5.214 +    // don't check blacklist or require a private key
   5.215 +    PEP_STATUS status = validate_fpr(session, ident, false, false);
   5.216 +
   5.217 +    if (status != PEP_STATUS_OK)
   5.218 +        return status;
   5.219 +
   5.220 +    status = set_pgp_keypair(session, ident->fpr);
   5.221 +    if (status != PEP_STATUS_OK)
   5.222 +        return status;
   5.223 +            
   5.224 +    if (ident->comm_type < PEP_ct_strong_but_unconfirmed)
   5.225 +        return PEP_KEY_UNSUITABLE;
   5.226 +
   5.227 +    ident->comm_type |= PEP_ct_confirmed;
   5.228 +    
   5.229 +    status = set_trust(session, ident);
   5.230 +
   5.231 +    return status;
   5.232 +}
   5.233 +
   5.234 +
   5.235  DYNAMIC_API PEP_STATUS own_key_is_listed(
   5.236          PEP_SESSION session,
   5.237          const char *fpr,
   5.238 @@ -1760,7 +1792,7 @@
   5.239      if (!me->fpr)
   5.240          return PEP_OUT_OF_MEMORY;
   5.241  
   5.242 -    status = validate_fpr(session, me, false);
   5.243 +    status = validate_fpr(session, me, false, true);
   5.244      if (status)
   5.245          return status;
   5.246  
   5.247 @@ -1953,4 +1985,3 @@
   5.248      return status;
   5.249  }
   5.250  #endif // USE_GPG
   5.251 -
     6.1 --- a/src/keymanagement.h	Mon Dec 24 15:32:27 2018 +0100
     6.2 +++ b/src/keymanagement.h	Wed Jan 23 11:59:43 2019 +0100
     6.3 @@ -211,21 +211,50 @@
     6.4  //
     6.5  //  parameters:
     6.6  //      session (in)        session to use
     6.7 -//      ident (in)          person and key to trust in
     6.8 +//      ident (in)          person and key to trust in - this must not be an
     6.9 +//                          own_identity in which the .me flag is set or
    6.10 +//                          the user_id is an own user_id.
    6.11  //
    6.12  //  caveat:
    6.13  //      the fields user_id, address and fpr must be supplied
    6.14 +//      own identities will result in a return of PEP_ILLEGAL_VALUE.
    6.15  //      for non-own users, this will 1) set the trust bit on its comm type in the DB,
    6.16  //      2) set this key as the identity default if the current identity default
    6.17  //      is not trusted, and 3) set this key as the user default if the current
    6.18  //      user default is not trusted.
    6.19 -//      For an own user, this is simply a call to myself().
    6.20  
    6.21  DYNAMIC_API PEP_STATUS trust_personal_key(
    6.22          PEP_SESSION session,
    6.23          pEp_identity *ident
    6.24      );
    6.25  
    6.26 +// trust_own_key() - mark a key as trusted for self, generally
    6.27 +//                   used when we need to trust a public key
    6.28 +//                   associated with outselves for issues like
    6.29 +//                   manual key import
    6.30 +//  parameters:
    6.31 +//      session (in)        session to use
    6.32 +//      ident (in)          own ident containing fpr to trust
    6.33 +//
    6.34 +//  caveat:
    6.35 +//      if this is a public key only, keep in mind that if
    6.36 +//      the private part of the keypair is later added,
    6.37 +//      it will not undergo separate trust evaluation. This
    6.38 +//      is fine - even desired - as long as the semantics
    6.39 +//      of this function are understood as both trusting
    6.40 +//      the key and verifying it as an own key. This will
    6.41 +//      NEVER cause replacement of or setting of a default
    6.42 +//      *alone*. However, if a private key is ever associated
    6.43 +//      with this fpr, please keep in mind that trusting it
    6.44 +//      here makes it an eligible key for selection for    
    6.45 +//      encryption later. So use this function on purpose with
    6.46 +//      an understanding of what you're doing!
    6.47 +//
    6.48 +DYNAMIC_API PEP_STATUS trust_own_key(
    6.49 +        PEP_SESSION session,
    6.50 +        pEp_identity *ident
    6.51 +    );
    6.52 +
    6.53  
    6.54  // key_reset_trust() - reset trust bit or explicitly mistrusted status for an identity and
    6.55  //                     its accompanying key/user_id pair.
     7.1 --- a/src/openpgp_compat.h	Mon Dec 24 15:32:27 2018 +0100
     7.2 +++ b/src/openpgp_compat.h	Wed Jan 23 11:59:43 2019 +0100
     7.3 @@ -24,6 +24,10 @@
     7.4  #else
     7.5  #ifdef USE_NETPGP
     7.6  #include "pgp_netpgp.h"
     7.7 +#else
     7.8 +#ifdef USE_SEQUOIA
     7.9 +#include "pgp_sequoia.h"
    7.10 +#endif
    7.11  #endif
    7.12  #endif    
    7.13      
     8.1 --- a/src/pEpEngine.h	Mon Dec 24 15:32:27 2018 +0100
     8.2 +++ b/src/pEpEngine.h	Wed Jan 23 11:59:43 2019 +0100
     8.3 @@ -162,6 +162,100 @@
     8.4  
     8.5  typedef int (*inject_sync_event_t)(SYNC_EVENT ev, void *management);
     8.6  
     8.7 +static inline const char *pep_status_to_string(PEP_STATUS status) {
     8.8 +    switch (status) {
     8.9 +    case PEP_STATUS_OK: return "PEP_STATUS_OK";
    8.10 +
    8.11 +    case PEP_INIT_CANNOT_LOAD_GPGME: return "PEP_INIT_CANNOT_LOAD_GPGME";
    8.12 +    case PEP_INIT_GPGME_INIT_FAILED: return "PEP_INIT_GPGME_INIT_FAILED";
    8.13 +    case PEP_INIT_NO_GPG_HOME: return "PEP_INIT_NO_GPG_HOME";
    8.14 +    case PEP_INIT_NETPGP_INIT_FAILED: return "PEP_INIT_NETPGP_INIT_FAILED";
    8.15 +    case PEP_INIT_CANNOT_DETERMINE_GPG_VERSION: return "PEP_INIT_CANNOT_DETERMINE_GPG_VERSION";
    8.16 +    case PEP_INIT_UNSUPPORTED_GPG_VERSION: return "PEP_INIT_UNSUPPORTED_GPG_VERSION";
    8.17 +    case PEP_INIT_CANNOT_CONFIG_GPG_AGENT: return "PEP_INIT_CANNOT_CONFIG_GPG_AGENT";
    8.18 +    case PEP_INIT_SQLITE3_WITHOUT_MUTEX: return "PEP_INIT_SQLITE3_WITHOUT_MUTEX";
    8.19 +    case PEP_INIT_CANNOT_OPEN_DB: return "PEP_INIT_CANNOT_OPEN_DB";
    8.20 +    case PEP_INIT_CANNOT_OPEN_SYSTEM_DB: return "PEP_INIT_CANNOT_OPEN_SYSTEM_DB";
    8.21 +    case PEP_UNKNOWN_DB_ERROR: return "PEP_UNKNOWN_DB_ERROR";
    8.22 +    case PEP_KEY_NOT_FOUND: return "PEP_KEY_NOT_FOUND";
    8.23 +    case PEP_KEY_HAS_AMBIG_NAME: return "PEP_KEY_HAS_AMBIG_NAME";
    8.24 +    case PEP_GET_KEY_FAILED: return "PEP_GET_KEY_FAILED";
    8.25 +    case PEP_CANNOT_EXPORT_KEY: return "PEP_CANNOT_EXPORT_KEY";
    8.26 +    case PEP_CANNOT_EDIT_KEY: return "PEP_CANNOT_EDIT_KEY";
    8.27 +    case PEP_KEY_UNSUITABLE: return "PEP_KEY_UNSUITABLE";
    8.28 +    case PEP_MALFORMED_KEY_RESET_MSG: return "PEP_MALFORMED_KEY_RESET_MSG";
    8.29 +    case PEP_KEY_NOT_RESET: return "PEP_KEY_NOT_RESET";
    8.30 +
    8.31 +    case PEP_CANNOT_FIND_IDENTITY: return "PEP_CANNOT_FIND_IDENTITY";
    8.32 +    case PEP_CANNOT_SET_PERSON: return "PEP_CANNOT_SET_PERSON";
    8.33 +    case PEP_CANNOT_SET_PGP_KEYPAIR: return "PEP_CANNOT_SET_PGP_KEYPAIR";
    8.34 +    case PEP_CANNOT_SET_IDENTITY: return "PEP_CANNOT_SET_IDENTITY";
    8.35 +    case PEP_CANNOT_SET_TRUST: return "PEP_CANNOT_SET_TRUST";
    8.36 +    case PEP_KEY_BLACKLISTED: return "PEP_KEY_BLACKLISTED";
    8.37 +    case PEP_CANNOT_FIND_PERSON: return "PEP_CANNOT_FIND_PERSON";
    8.38 +
    8.39 +    case PEP_CANNOT_FIND_ALIAS: return "PEP_CANNOT_FIND_ALIAS";
    8.40 +    case PEP_CANNOT_SET_ALIAS: return "PEP_CANNOT_SET_ALIAS";
    8.41 +
    8.42 +    case PEP_UNENCRYPTED: return "PEP_UNENCRYPTED";
    8.43 +    case PEP_VERIFIED: return "PEP_VERIFIED";
    8.44 +    case PEP_DECRYPTED: return "PEP_DECRYPTED";
    8.45 +    case PEP_DECRYPTED_AND_VERIFIED: return "PEP_DECRYPTED_AND_VERIFIED";
    8.46 +    case PEP_DECRYPT_WRONG_FORMAT: return "PEP_DECRYPT_WRONG_FORMAT";
    8.47 +    case PEP_DECRYPT_NO_KEY: return "PEP_DECRYPT_NO_KEY";
    8.48 +    case PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH: return "PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH";
    8.49 +    case PEP_VERIFY_NO_KEY: return "PEP_VERIFY_NO_KEY";
    8.50 +    case PEP_VERIFIED_AND_TRUSTED: return "PEP_VERIFIED_AND_TRUSTED";
    8.51 +    case PEP_CANNOT_REENCRYPT: return "PEP_CANNOT_REENCRYPT";
    8.52 +    case PEP_CANNOT_DECRYPT_UNKNOWN: return "PEP_CANNOT_DECRYPT_UNKNOWN";
    8.53 +
    8.54 +    case PEP_TRUSTWORD_NOT_FOUND: return "PEP_TRUSTWORD_NOT_FOUND";
    8.55 +    case PEP_TRUSTWORDS_FPR_WRONG_LENGTH: return "PEP_TRUSTWORDS_FPR_WRONG_LENGTH";
    8.56 +    case PEP_TRUSTWORDS_DUPLICATE_FPR: return "PEP_TRUSTWORDS_DUPLICATE_FPR";
    8.57 +
    8.58 +    case PEP_CANNOT_CREATE_KEY: return "PEP_CANNOT_CREATE_KEY";
    8.59 +    case PEP_CANNOT_SEND_KEY: return "PEP_CANNOT_SEND_KEY";
    8.60 +
    8.61 +    case PEP_PHRASE_NOT_FOUND: return "PEP_PHRASE_NOT_FOUND";
    8.62 +
    8.63 +    case PEP_SEND_FUNCTION_NOT_REGISTERED: return "PEP_SEND_FUNCTION_NOT_REGISTERED";
    8.64 +    case PEP_CONTRAINTS_VIOLATED: return "PEP_CONTRAINTS_VIOLATED";
    8.65 +    case PEP_CANNOT_ENCODE: return "PEP_CANNOT_ENCODE";
    8.66 +
    8.67 +    case PEP_SYNC_NO_NOTIFY_CALLBACK: return "PEP_SYNC_NO_NOTIFY_CALLBACK";
    8.68 +    case PEP_SYNC_ILLEGAL_MESSAGE: return "PEP_SYNC_ILLEGAL_MESSAGE";
    8.69 +    case PEP_SYNC_NO_INJECT_CALLBACK: return "PEP_SYNC_NO_INJECT_CALLBACK";
    8.70 +    case PEP_SYNC_NO_CHANNEL: return "PEP_SYNC_NO_CHANNEL";
    8.71 +    case PEP_SYNC_CANNOT_ENCRYPT: return "PEP_SYNC_CANNOT_ENCRYPT";
    8.72 +    case PEP_SYNC_NO_MESSAGE_SEND_CALLBACK: return "PEP_SYNC_NO_MESSAGE_SEND_CALLBACK";
    8.73 +
    8.74 +    case PEP_CANNOT_INCREASE_SEQUENCE: return "PEP_CANNOT_INCREASE_SEQUENCE";
    8.75 +
    8.76 +    case PEP_STATEMACHINE_ERROR: return "PEP_STATEMACHINE_ERROR";
    8.77 +    case PEP_NO_TRUST: return "PEP_NO_TRUST";
    8.78 +    case PEP_STATEMACHINE_INVALID_STATE: return "PEP_STATEMACHINE_INVALID_STATE";
    8.79 +    case PEP_STATEMACHINE_INVALID_EVENT: return "PEP_STATEMACHINE_INVALID_EVENT";
    8.80 +    case PEP_STATEMACHINE_INVALID_CONDITION: return "PEP_STATEMACHINE_INVALID_CONDITION";
    8.81 +    case PEP_STATEMACHINE_INVALID_ACTION: return "PEP_STATEMACHINE_INVALID_ACTION";
    8.82 +    case PEP_STATEMACHINE_INHIBITED_EVENT: return "PEP_STATEMACHINE_INHIBITED_EVENT";
    8.83 +    case PEP_STATEMACHINE_CANNOT_SEND: return "PEP_STATEMACHINE_CANNOT_SEND";
    8.84 +
    8.85 +    case PEP_COMMIT_FAILED: return "PEP_COMMIT_FAILED";
    8.86 +    case PEP_MESSAGE_CONSUME: return "PEP_MESSAGE_CONSUME";
    8.87 +    case PEP_MESSAGE_IGNORE: return "PEP_MESSAGE_IGNORE";
    8.88 +
    8.89 +    case PEP_RECORD_NOT_FOUND: return "PEP_RECORD_NOT_FOUND";
    8.90 +    case PEP_CANNOT_CREATE_TEMP_FILE: return "PEP_CANNOT_CREATE_TEMP_FILE";
    8.91 +    case PEP_ILLEGAL_VALUE: return "PEP_ILLEGAL_VALUE";
    8.92 +    case PEP_BUFFER_TOO_SMALL: return "PEP_BUFFER_TOO_SMALL";
    8.93 +    case PEP_OUT_OF_MEMORY: return "PEP_OUT_OF_MEMORY";
    8.94 +    case PEP_UNKNOWN_ERROR: return "PEP_UNKNOWN_ERROR";
    8.95 +
    8.96 +    case PEP_VERSION_MISMATCH: return "PEP_VERSION_MISMATCH";
    8.97 +
    8.98 +    default: return "unknown status code";
    8.99 +    }
   8.100 +}
   8.101  
   8.102  // INIT_STATUS init() - initialize pEpEngine for a thread
   8.103  //
   8.104 @@ -535,6 +629,47 @@
   8.105      PEP_ct_pEp = 0xff
   8.106  } PEP_comm_type;
   8.107  
   8.108 +static inline const char *pep_comm_type_to_string(PEP_comm_type ct) {
   8.109 +    switch (ct) {
   8.110 +    case PEP_ct_unknown: return "unknown";
   8.111 +    case PEP_ct_no_encryption: return "no_encryption";
   8.112 +    case PEP_ct_no_encrypted_channel: return "no_encrypted_channel";
   8.113 +    case PEP_ct_key_not_found: return "key_not_found";
   8.114 +    case PEP_ct_key_expired: return "key_expired";
   8.115 +    case PEP_ct_key_revoked: return "key_revoked";
   8.116 +    case PEP_ct_key_b0rken: return "key_b0rken";
   8.117 +    case PEP_ct_my_key_not_included: return "my_key_not_included";
   8.118 +    case PEP_ct_security_by_obscurity: return "security_by_obscurity";
   8.119 +    case PEP_ct_b0rken_crypto: return "b0rken_crypto";
   8.120 +    case PEP_ct_key_too_short: return "key_too_short";
   8.121 +    case PEP_ct_compromised: return "compromised";
   8.122 +    case PEP_ct_mistrusted: return "mistrusted";
   8.123 +    case PEP_ct_unconfirmed_encryption: return "unconfirmed_encryption";
   8.124 +    case PEP_ct_OpenPGP_weak_unconfirmed: return "OpenPGP_weak_unconfirmed";
   8.125 +    case PEP_ct_to_be_checked: return "to_be_checked";
   8.126 +    case PEP_ct_SMIME_unconfirmed: return "SMIME_unconfirmed";
   8.127 +    case PEP_ct_CMS_unconfirmed: return "CMS_unconfirmed";
   8.128 +    case PEP_ct_strong_but_unconfirmed: return "strong_but_unconfirmed";
   8.129 +    case PEP_ct_OpenPGP_unconfirmed: return "OpenPGP_unconfirmed";
   8.130 +    case PEP_ct_OTR_unconfirmed: return "OTR_unconfirmed";
   8.131 +    case PEP_ct_unconfirmed_enc_anon: return "unconfirmed_enc_anon";
   8.132 +    case PEP_ct_pEp_unconfirmed: return "pEp_unconfirmed";
   8.133 +    case PEP_ct_confirmed: return "confirmed";
   8.134 +    case PEP_ct_confirmed_encryption: return "confirmed_encryption";
   8.135 +    case PEP_ct_OpenPGP_weak: return "OpenPGP_weak";
   8.136 +    case PEP_ct_to_be_checked_confirmed: return "to_be_checked_confirmed";
   8.137 +    case PEP_ct_SMIME: return "SMIME";
   8.138 +    case PEP_ct_CMS: return "CMS";
   8.139 +    case PEP_ct_strong_encryption: return "strong_encryption";
   8.140 +    case PEP_ct_OpenPGP: return "OpenPGP";
   8.141 +    case PEP_ct_OTR: return "OTR";
   8.142 +    case PEP_ct_confirmed_enc_anon: return "confirmed_enc_anon";
   8.143 +    case PEP_ct_pEp: return "pEp";
   8.144 +    default: return "invalid comm type";
   8.145 +    }
   8.146 +}
   8.147 +
   8.148 +
   8.149  typedef enum _identity_flags {
   8.150      // the first octet flags are app defined settings
   8.151      PEP_idf_not_for_sync = 0x0001,   // don't use this identity for sync
     9.1 --- a/src/pEp_internal.h	Mon Dec 24 15:32:27 2018 +0100
     9.2 +++ b/src/pEp_internal.h	Wed Jan 23 11:59:43 2019 +0100
     9.3 @@ -91,16 +91,20 @@
     9.4  #include "pEpEngine.h"
     9.5  
     9.6  // If not specified, build for GPG
     9.7 +#ifndef USE_SEQUOIA
     9.8  #ifndef USE_NETPGP
     9.9  #ifndef USE_GPG
    9.10  #define USE_GPG
    9.11  #endif
    9.12  #endif
    9.13 +#endif
    9.14  
    9.15  #ifdef USE_GPG
    9.16  #include "pgp_gpg_internal.h"
    9.17  #elif defined(USE_NETPGP)
    9.18  #include "pgp_netpgp_internal.h"
    9.19 +#elif defined(USE_SEQUOIA)
    9.20 +#include "pgp_sequoia_internal.h"
    9.21  #endif
    9.22  
    9.23  #include "keymanagement.h"
    9.24 @@ -123,6 +127,25 @@
    9.25      gpgme_ctx_t ctx;
    9.26  #elif defined(USE_NETPGP)
    9.27      pEpNetPGPSession ctx;
    9.28 +#elif defined(USE_SEQUOIA)
    9.29 +    sq_context_t ctx;
    9.30 +    sqlite3 *key_db;
    9.31 +    struct {
    9.32 +        sqlite3_stmt *begin_transaction;
    9.33 +        sqlite3_stmt *commit_transaction;
    9.34 +        sqlite3_stmt *rollback_transaction;
    9.35 +        sqlite3_stmt *tpk_find;
    9.36 +        sqlite3_stmt *tsk_find;
    9.37 +        sqlite3_stmt *tpk_find_by_keyid;
    9.38 +        sqlite3_stmt *tsk_find_by_keyid;
    9.39 +        sqlite3_stmt *tpk_find_by_email;
    9.40 +        sqlite3_stmt *tsk_find_by_email;
    9.41 +        sqlite3_stmt *tpk_all;
    9.42 +        sqlite3_stmt *tsk_all;
    9.43 +        sqlite3_stmt *tpk_save_insert_primary;
    9.44 +        sqlite3_stmt *tpk_save_insert_subkeys;
    9.45 +        sqlite3_stmt *tpk_save_insert_userids;
    9.46 +    } sq_sql;
    9.47  #endif
    9.48  
    9.49      PEP_cryptotech_t *cryptotech;
    10.1 --- a/src/pgp_gpg.c	Mon Dec 24 15:32:27 2018 +0100
    10.2 +++ b/src/pgp_gpg.c	Wed Jan 23 11:59:43 2019 +0100
    10.3 @@ -361,6 +361,7 @@
    10.4          DLOAD(gpgme_signers_add);
    10.5          DLOAD(gpgme_set_passphrase_cb);
    10.6          DLOAD(gpgme_get_key);
    10.7 +        DLOAD(gpgme_strerror);
    10.8          
    10.9  #ifdef GPGME_VERSION_NUMBER
   10.10  #if (GPGME_VERSION_NUMBER >= 0x010700)
   10.11 @@ -2141,31 +2142,63 @@
   10.12              *comm_type = PEP_ct_key_revoked;            
   10.13          else if (key->expired)
   10.14              *comm_type = PEP_ct_key_expired;
   10.15 +        else if (!key->subkeys)
   10.16 +            *comm_type = PEP_ct_key_b0rken;
   10.17          else {
   10.18              // Ok, so we now need to check subkeys. Normally, we could just
   10.19              // shortcut this by looking at key->can_sign and key->can_encrypt,
   10.20              // but we want the REASON we can't use a key, so this gets ugly.
   10.21              PEP_comm_type max_comm_type = *comm_type;
   10.22 -                        
   10.23 -            PEP_comm_type best_sign = PEP_ct_no_encryption;
   10.24 -            PEP_comm_type best_enc = PEP_ct_no_encryption;
   10.25 -            
   10.26 +
   10.27 +            // NOTE: 
   10.28 +            // PEP_ct_pEp functions here as an unreachable top;
   10.29 +            // it is impossible on just a key.
   10.30 +            // IF THIS CHANGES, we must choose something else.
   10.31 +            PEP_comm_type worst_sign = PEP_ct_pEp;
   10.32 +            PEP_comm_type worst_enc = PEP_ct_pEp;
   10.33 +
   10.34 +            PEP_comm_type error_sign = PEP_ct_unknown;
   10.35 +            PEP_comm_type error_enc = PEP_ct_unknown;
   10.36 +
   10.37 +            // We require that the underlying client NOT force-use expired or revoked
   10.38 +            // subkeys instead of a valid one.
   10.39 +            //
   10.40 +            // So here we check all the subkeys; we make note of the existence
   10.41 +            // of an expired, revoked, or invalid subkey, in case there is no
   10.42 +            // other alternative (we want to return useful information).
   10.43 +            // At the same time, we try to evaluate the least strong useable keys 
   10.44 +            // for signing and encryption. If there is a useable one of both,
   10.45 +            // the key comm_type corresponds to the lesser of these two least strong
   10.46 +            // keys
   10.47              for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
   10.48 +                
   10.49 +                // Only evaluate signing keys or encryption keys
   10.50                  if (sk->can_sign || sk->can_encrypt) {
   10.51                      PEP_comm_type curr_sign = PEP_ct_no_encryption;
   10.52                      PEP_comm_type curr_enc = PEP_ct_no_encryption;
   10.53 -                    
   10.54 -                    if (sk->length < 1024) {
   10.55 +
   10.56 +#ifdef GPGME_PK_ECC                    
   10.57 +                    if ((sk->pubkey_algo != GPGME_PK_ECC && sk->length < 1024) 
   10.58 +                        || (sk->pubkey_algo == GPGME_PK_ECC && sk->length < 160)) {
   10.59 +#else
   10.60 +                    if (sk->length < 1024) {                        
   10.61 +#endif                        
   10.62                          if (sk->can_sign)
   10.63                              curr_sign = PEP_ct_key_too_short;
   10.64                          if (sk->can_encrypt)                               
   10.65                              curr_enc = PEP_ct_key_too_short;
   10.66                      }
   10.67 -                    else if (
   10.68 -                        ((sk->pubkey_algo == GPGME_PK_RSA)
   10.69 -                        || (sk->pubkey_algo == GPGME_PK_RSA_E)
   10.70 -                        || (sk->pubkey_algo == GPGME_PK_RSA_S))
   10.71 -                        && sk->length == 1024) {
   10.72 +                    else if 
   10.73 +                        (
   10.74 +                            (((sk->pubkey_algo == GPGME_PK_RSA)
   10.75 +                                || (sk->pubkey_algo == GPGME_PK_RSA_E)
   10.76 +                                || (sk->pubkey_algo == GPGME_PK_RSA_S))
   10.77 +                                && sk->length == 1024)
   10.78 +#ifdef GPGME_PK_ECC                    
   10.79 +                            || (sk->pubkey_algo == GPGME_PK_ECC
   10.80 +                                && sk->length == 160)
   10.81 +#endif                             
   10.82 +                        ) {
   10.83                          if (sk->can_sign)
   10.84                              curr_sign = PEP_ct_OpenPGP_weak_unconfirmed;
   10.85                          if (sk->can_encrypt)                               
   10.86 @@ -2195,18 +2228,39 @@
   10.87                          if (sk->can_encrypt)                               
   10.88                              curr_enc = PEP_ct_key_revoked;
   10.89                      }
   10.90 -                    if (sk->can_sign)
   10.91 -                        best_sign = _MAX(curr_sign, best_sign);
   10.92 -                    if (sk->can_encrypt)
   10.93 -                        best_enc = _MAX(curr_enc, best_enc);
   10.94 +                    switch (curr_sign) {
   10.95 +                        case PEP_ct_key_b0rken:
   10.96 +                        case PEP_ct_key_expired:
   10.97 +                        case PEP_ct_key_revoked:
   10.98 +                            error_sign = curr_sign;
   10.99 +                            break;
  10.100 +                        default:    
  10.101 +                            if (sk->can_sign)
  10.102 +                                worst_sign = _MIN(curr_sign, worst_sign);
  10.103 +                            break;
  10.104 +                    }
  10.105 +                    switch (curr_enc) {
  10.106 +                        case PEP_ct_key_b0rken:
  10.107 +                        case PEP_ct_key_expired:
  10.108 +                        case PEP_ct_key_revoked:
  10.109 +                            error_sign = curr_sign;
  10.110 +                            break;
  10.111 +                        default:    
  10.112 +                            if (sk->can_encrypt)
  10.113 +                                worst_enc = _MIN(curr_enc, worst_enc);
  10.114 +                            break;
  10.115 +                    }                    
  10.116                  }    
  10.117              }
  10.118 -            if (best_enc == PEP_ct_no_encryption ||
  10.119 -                best_sign == PEP_ct_no_encryption) {
  10.120 -                *comm_type = PEP_ct_key_b0rken;
  10.121 +            if (worst_enc == PEP_ct_pEp ||
  10.122 +                worst_sign == PEP_ct_pEp) {
  10.123 +                // No valid key was found for one or both; return a useful 
  10.124 +                // error comm_type
  10.125 +                PEP_comm_type error_ct = _MAX(error_enc, error_sign);    
  10.126 +                *comm_type = (error_ct == PEP_ct_unknown ? PEP_ct_key_b0rken : error_ct);
  10.127              }
  10.128              else {
  10.129 -                *comm_type = _MIN(best_sign, _MIN(max_comm_type, best_enc));
  10.130 +                *comm_type = _MIN(max_comm_type, _MIN(worst_sign, worst_enc));
  10.131              }                
  10.132          }
  10.133          break;
    11.1 --- a/src/pgp_gpg_internal.h	Mon Dec 24 15:32:27 2018 +0100
    11.2 +++ b/src/pgp_gpg_internal.h	Wed Jan 23 11:59:43 2019 +0100
    11.3 @@ -83,6 +83,8 @@
    11.4          gpgme_edit_cb_t FNC, void *HANDLE, gpgme_data_t OUT);
    11.5  typedef gpgme_ssize_t (*gpgme_io_write_t)(int fd, const void *buffer,
    11.6          size_t count);
    11.7 +typedef const char*(*gpgme_strerror_t)(gpgme_error_t err);
    11.8 +
    11.9  
   11.10  #ifdef GPGME_VERSION_NUMBER 
   11.11  #if (GPGME_VERSION_NUMBER >= 0x010700)
   11.12 @@ -153,6 +155,8 @@
   11.13  	gpgme_key_release_t gpgme_key_release;
   11.14      gpgme_op_edit_t gpgme_op_edit;
   11.15      gpgme_io_write_t gpgme_io_write;
   11.16 +    
   11.17 +    gpgme_strerror_t gpgme_strerror;
   11.18  
   11.19      gpgme_set_passphrase_cb_t gpgme_set_passphrase_cb;
   11.20  };
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/pgp_sequoia.c	Wed Jan 23 11:59:43 2019 +0100
    12.3 @@ -0,0 +1,2116 @@
    12.4 +// This file is under GNU General Public License 3.0
    12.5 +// see LICENSE.txt
    12.6 +
    12.7 +#define _GNU_SOURCE 1
    12.8 +
    12.9 +#include "platform.h"
   12.10 +#include "pEp_internal.h"
   12.11 +#include "pgp_gpg.h"
   12.12 +
   12.13 +#include <limits.h>
   12.14 +#include <sys/stat.h>
   12.15 +#include <sys/types.h>
   12.16 +#include <error.h>
   12.17 +
   12.18 +#include <sqlite3.h>
   12.19 +
   12.20 +#include "wrappers.h"
   12.21 +
   12.22 +#define TRACE 0
   12.23 +#ifndef TRACING
   12.24 +#  ifndef NDEBUG
   12.25 +#    define TRACING 0
   12.26 +#  else
   12.27 +#    define TRACING 1
   12.28 +#  endif
   12.29 +#endif
   12.30 +
   12.31 +// enable tracing if in debugging mode
   12.32 +#if TRACING
   12.33 +#  define _T(...) do {                          \
   12.34 +        fprintf(stderr, ##__VA_ARGS__);         \
   12.35 +    } while (0)
   12.36 +#else
   12.37 +#  define _T(...) do { } while (0)
   12.38 +#endif
   12.39 +
   12.40 +// Show the start of a tracepoint (i.e., don't print a newline).
   12.41 +#define TC(...) do {       \
   12.42 +    _T("%s: ", __func__);  \
   12.43 +    _T(__VA_ARGS__);       \
   12.44 +} while (0)
   12.45 +
   12.46 +// Show a trace point.
   12.47 +#  define T(...) do {  \
   12.48 +    TC(__VA_ARGS__); \
   12.49 +    _T("\n");          \
   12.50 +} while(0)
   12.51 +
   12.52 +// Verbosely displays errors.
   12.53 +#  define DUMP_ERR(__de_session, __de_status, ...) do {             \
   12.54 +    TC(__VA_ARGS__);                                                \
   12.55 +    _T(": ");                                                       \
   12.56 +    if ((__de_session->ctx)) {                                      \
   12.57 +        sq_error_t __de_err                                         \
   12.58 +            = sq_context_last_error((__de_session->ctx));           \
   12.59 +        if (__de_err)                                               \
   12.60 +            _T("Sequoia: %s => ", sq_error_string(__de_err));       \
   12.61 +        sq_error_free(__de_err);                                    \
   12.62 +    }                                                               \
   12.63 +    _T("%s\n", pep_status_to_string(__de_status));                  \
   12.64 +} while(0)
   12.65 +
   12.66 +// If __ec_status is an error, then disable the error, set 'status' to
   12.67 +// it, and jump to 'out'.
   12.68 +#define ERROR_OUT(__e_session, __ec_status, ...) do {               \
   12.69 +    PEP_STATUS ___ec_status = (__ec_status);                        \
   12.70 +    if ((___ec_status) != PEP_STATUS_OK) {                          \
   12.71 +        DUMP_ERR((__e_session), (___ec_status), ##__VA_ARGS__);     \
   12.72 +        status = (___ec_status);                                    \
   12.73 +        goto out;                                                   \
   12.74 +    }                                                               \
   12.75 +} while(0)
   12.76 +
   12.77 +PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
   12.78 +{
   12.79 +    PEP_STATUS status = PEP_STATUS_OK;
   12.80 +
   12.81 +    sq_error_t err;
   12.82 +    session->ctx = sq_context_new("foundation.pep", &err);
   12.83 +    if (session->ctx == NULL)
   12.84 +        ERROR_OUT(session, PEP_INIT_GPGME_INIT_FAILED,
   12.85 +                  "initializing sequoia context");
   12.86 +
   12.87 +    // Create the home directory.
   12.88 +    char *home_env = getenv("HOME");
   12.89 +    if (!home_env)
   12.90 +        ERROR_OUT(session, PEP_INIT_GPGME_INIT_FAILED, "HOME unset");
   12.91 +
   12.92 +    // Create the DB and initialize it.
   12.93 +    char *path = NULL;
   12.94 +    asprintf(&path, "%s/.pEp_keys.db", home_env);
   12.95 +    if (!path)
   12.96 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
   12.97 +
   12.98 +    int sqlite_result;
   12.99 +    sqlite_result = sqlite3_open_v2(path,
  12.100 +                                    &session->key_db,
  12.101 +                                    SQLITE_OPEN_READWRITE
  12.102 +                                    | SQLITE_OPEN_CREATE
  12.103 +                                    | SQLITE_OPEN_FULLMUTEX
  12.104 +                                    | SQLITE_OPEN_PRIVATECACHE,
  12.105 +                                    NULL);
  12.106 +    free(path);
  12.107 +    if (sqlite_result != SQLITE_OK)
  12.108 +        ERROR_OUT(session, PEP_INIT_CANNOT_OPEN_DB,
  12.109 +                  "opening keys DB: %s",
  12.110 +                  sqlite3_errmsg(session->key_db));
  12.111 +
  12.112 +    sqlite_result = sqlite3_exec(session->key_db,
  12.113 +                                 "PRAGMA secure_delete=true;\n"
  12.114 +                                 "PRAGMA foreign_keys=true;\n"
  12.115 +                                 "PRAGMA locking_mode=NORMAL;\n"
  12.116 +                                 "PRAGMA journal_mode=WAL;\n",
  12.117 +                                 NULL, NULL, NULL);
  12.118 +    if (sqlite_result != SQLITE_OK)
  12.119 +        ERROR_OUT(session, PEP_INIT_CANNOT_OPEN_DB,
  12.120 +                  "setting pragmas: %s", sqlite3_errmsg(session->key_db));
  12.121 +
  12.122 +    sqlite3_busy_timeout(session->key_db, BUSY_WAIT_TIME);
  12.123 +
  12.124 +    sqlite_result = sqlite3_exec(session->key_db,
  12.125 +                                 "CREATE TABLE IF NOT EXISTS keys (\n"
  12.126 +                                 "   primary_key TEXT UNIQUE PRIMARY KEY,\n"
  12.127 +                                 "   secret BOOLEAN,\n"
  12.128 +                                 "   tpk BLOB\n"
  12.129 +                                 ");\n"
  12.130 +                                 "CREATE INDEX IF NOT EXISTS keys_index\n"
  12.131 +                                 "  ON keys (primary_key, secret)\n",
  12.132 +                                 NULL, NULL, NULL);
  12.133 +    if (sqlite_result != SQLITE_OK)
  12.134 +        ERROR_OUT(session, PEP_INIT_CANNOT_OPEN_DB,
  12.135 +                  "creating keys table: %s",
  12.136 +                  sqlite3_errmsg(session->key_db));
  12.137 +
  12.138 +    sqlite_result = sqlite3_exec(session->key_db,
  12.139 +                                 "CREATE TABLE IF NOT EXISTS subkeys (\n"
  12.140 +                                 "   subkey TEXT NOT NULL,\n"
  12.141 +                                 "   primary_key TEXT NOT NULL,\n"
  12.142 +                                 "   UNIQUE(subkey, primary_key),\n"
  12.143 +                                 "   FOREIGN KEY (primary_key)\n"
  12.144 +                                 "       REFERENCES keys(primary_key)\n"
  12.145 +                                 "     ON DELETE CASCADE\n"
  12.146 +                                 ");\n"
  12.147 +                                 "CREATE INDEX IF NOT EXISTS subkeys_index\n"
  12.148 +                                 "  ON subkeys (subkey, primary_key)\n",
  12.149 +                                 NULL, NULL, NULL);
  12.150 +    if (sqlite_result != SQLITE_OK)
  12.151 +        ERROR_OUT(session, PEP_INIT_CANNOT_OPEN_DB,
  12.152 +                  "creating subkeys table: %s",
  12.153 +                  sqlite3_errmsg(session->key_db));
  12.154 +
  12.155 +    sqlite_result = sqlite3_exec(session->key_db,
  12.156 +                                 "CREATE TABLE IF NOT EXISTS userids (\n"
  12.157 +                                 "   userid TEXT NOT NULL,\n"
  12.158 +                                 "   primary_key TEXT NOT NULL,\n"
  12.159 +                                 "   UNIQUE(userid, primary_key),\n"
  12.160 +                                 "   FOREIGN KEY (primary_key)\n"
  12.161 +                                 "       REFERENCES keys(primary_key)\n"
  12.162 +                                 "     ON DELETE CASCADE\n"
  12.163 +                                 ");\n"
  12.164 +                                 "CREATE INDEX IF NOT EXISTS userids_index\n"
  12.165 +                                 "  ON userids (userid, primary_key)\n",
  12.166 +                                 NULL, NULL, NULL);
  12.167 +    if (sqlite_result != SQLITE_OK)
  12.168 +        ERROR_OUT(session, PEP_INIT_CANNOT_OPEN_DB,
  12.169 +                  "creating userids table: %s",
  12.170 +                  sqlite3_errmsg(session->key_db));
  12.171 +
  12.172 +    sqlite_result
  12.173 +        = sqlite3_prepare_v2(session->key_db, "begin transaction",
  12.174 +                             -1, &session->sq_sql.begin_transaction, NULL);
  12.175 +    assert(sqlite_result == SQLITE_OK);
  12.176 +
  12.177 +    sqlite_result
  12.178 +        = sqlite3_prepare_v2(session->key_db, "commit transaction",
  12.179 +                             -1, &session->sq_sql.commit_transaction, NULL);
  12.180 +    assert(sqlite_result == SQLITE_OK);
  12.181 +
  12.182 +    sqlite_result
  12.183 +        = sqlite3_prepare_v2(session->key_db, "rollback transaction",
  12.184 +                             -1, &session->sq_sql.rollback_transaction, NULL);
  12.185 +    assert(sqlite_result == SQLITE_OK);
  12.186 +
  12.187 +    sqlite_result
  12.188 +        = sqlite3_prepare_v2(session->key_db,
  12.189 +                             "SELECT tpk, secret FROM keys"
  12.190 +                             " WHERE primary_key == ?",
  12.191 +                             -1, &session->sq_sql.tpk_find, NULL);
  12.192 +    assert(sqlite_result == SQLITE_OK);
  12.193 +
  12.194 +    sqlite_result
  12.195 +        = sqlite3_prepare_v2(session->key_db,
  12.196 +                             "SELECT tpk, secret FROM keys"
  12.197 +                             " WHERE primary_key == ? and secret == 1",
  12.198 +                             -1, &session->sq_sql.tsk_find, NULL);
  12.199 +    assert(sqlite_result == SQLITE_OK);
  12.200 +
  12.201 +    sqlite_result
  12.202 +        = sqlite3_prepare_v2(session->key_db,
  12.203 +                             "SELECT tpk, secret FROM subkeys"
  12.204 +                             " LEFT JOIN keys"
  12.205 +                             "  ON subkeys.primary_key == keys.primary_key"
  12.206 +                             " WHERE subkey == ?",
  12.207 +                             -1, &session->sq_sql.tpk_find_by_keyid, NULL);
  12.208 +    assert(sqlite_result == SQLITE_OK);
  12.209 +
  12.210 +    sqlite_result
  12.211 +        = sqlite3_prepare_v2(session->key_db,
  12.212 +                             "SELECT tpk, secret FROM subkeys"
  12.213 +                             " LEFT JOIN keys"
  12.214 +                             "  ON subkeys.primary_key == keys.primary_key"
  12.215 +                             " WHERE subkey == ?",
  12.216 +                             -1, &session->sq_sql.tpk_find_by_keyid, NULL);
  12.217 +    assert(sqlite_result == SQLITE_OK);
  12.218 +
  12.219 +    sqlite_result
  12.220 +        = sqlite3_prepare_v2(session->key_db,
  12.221 +                             "SELECT tpk, secret FROM subkeys"
  12.222 +                             " LEFT JOIN keys"
  12.223 +                             "  ON subkeys.primary_key == keys.primary_key"
  12.224 +                             " WHERE subkey == ? and keys.secret == 1",
  12.225 +                             -1, &session->sq_sql.tsk_find_by_keyid, NULL);
  12.226 +    assert(sqlite_result == SQLITE_OK);
  12.227 +
  12.228 +    sqlite_result
  12.229 +        = sqlite3_prepare_v2(session->key_db,
  12.230 +                             "SELECT tpk, secret FROM userids"
  12.231 +                             " LEFT JOIN keys"
  12.232 +                             "  ON userids.primary_key == keys.primary_key"
  12.233 +                             " WHERE userid == ?",
  12.234 +                             -1, &session->sq_sql.tpk_find_by_email, NULL);
  12.235 +    assert(sqlite_result == SQLITE_OK);
  12.236 +
  12.237 +    sqlite_result
  12.238 +        = sqlite3_prepare_v2(session->key_db,
  12.239 +                             "SELECT tpk, secret FROM userids"
  12.240 +                             " LEFT JOIN keys"
  12.241 +                             "  ON userids.primary_key == keys.primary_key"
  12.242 +                             " WHERE userid == ? and keys.secret == 1",
  12.243 +                             -1, &session->sq_sql.tsk_find_by_email, NULL);
  12.244 +    assert(sqlite_result == SQLITE_OK);
  12.245 +
  12.246 +    sqlite_result
  12.247 +        = sqlite3_prepare_v2(session->key_db,
  12.248 +                             "select tpk, secret from keys",
  12.249 +                             -1, &session->sq_sql.tpk_all, NULL);
  12.250 +    assert(sqlite_result == SQLITE_OK);
  12.251 +
  12.252 +    sqlite_result
  12.253 +        = sqlite3_prepare_v2(session->key_db,
  12.254 +                             "select tpk, secret from keys where secret = 1",
  12.255 +                             -1, &session->sq_sql.tsk_all, NULL);
  12.256 +    assert(sqlite_result == SQLITE_OK);
  12.257 +
  12.258 +    sqlite_result
  12.259 +        = sqlite3_prepare_v2(session->key_db,
  12.260 +                             "INSERT OR REPLACE INTO keys"
  12.261 +                             "   (primary_key, secret, tpk)"
  12.262 +                             " VALUES (?, ?, ?)",
  12.263 +                             -1, &session->sq_sql.tpk_save_insert_primary, NULL);
  12.264 +    assert(sqlite_result == SQLITE_OK);
  12.265 +
  12.266 +    sqlite_result
  12.267 +        = sqlite3_prepare_v2(session->key_db,
  12.268 +                             "INSERT OR REPLACE INTO subkeys"
  12.269 +                             "   (subkey, primary_key)"
  12.270 +                             " VALUES (?, ?)",
  12.271 +                             -1, &session->sq_sql.tpk_save_insert_subkeys, NULL);
  12.272 +    assert(sqlite_result == SQLITE_OK);
  12.273 +
  12.274 +    sqlite_result
  12.275 +        = sqlite3_prepare_v2(session->key_db,
  12.276 +                             "INSERT OR REPLACE INTO userids"
  12.277 +                             "   (userid, primary_key)"
  12.278 +                             " VALUES (?, ?)",
  12.279 +                             -1, &session->sq_sql.tpk_save_insert_userids, NULL);
  12.280 +    assert(sqlite_result == SQLITE_OK);
  12.281 +
  12.282 + out:
  12.283 +    if (status != PEP_STATUS_OK)
  12.284 +        pgp_release(session, in_first);
  12.285 +    return status;
  12.286 +}
  12.287 +
  12.288 +void pgp_release(PEP_SESSION session, bool out_last)
  12.289 +{
  12.290 +    sqlite3_stmt **stmts = (sqlite3_stmt **) &session->sq_sql;
  12.291 +    for (int i = 0; i < sizeof(session->sq_sql) / sizeof(*stmts); i ++)
  12.292 +        if (stmts[i]) {
  12.293 +            sqlite3_finalize(stmts[i]);
  12.294 +            stmts[i] = NULL;
  12.295 +        }
  12.296 +
  12.297 +    if (session->key_db) {
  12.298 +        int result = sqlite3_close_v2(session->key_db);
  12.299 +        if (result != 0)
  12.300 +            DUMP_ERR(session, PEP_UNKNOWN_ERROR,
  12.301 +                     "Closing key DB: sqlite3_close_v2: %s",
  12.302 +                     sqlite3_errstr(result));
  12.303 +        session->key_db = NULL;
  12.304 +    }
  12.305 +
  12.306 +    if (session->ctx) {
  12.307 +        sq_context_free(session->ctx);
  12.308 +        session->ctx = NULL;
  12.309 +    }
  12.310 +}
  12.311 +
  12.312 +// Ensures that a fingerprint is in canonical form.  A canonical
  12.313 +// fingerprint doesn't contain any white space.
  12.314 +//
  12.315 +// This function does *not* consume fpr.
  12.316 +static char *sq_fingerprint_canonicalize(const char *) __attribute__((nonnull));
  12.317 +static char *sq_fingerprint_canonicalize(const char *fpr)
  12.318 +{
  12.319 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
  12.320 +    char *fpr_canonicalized = sq_fingerprint_to_hex(sq_fpr);
  12.321 +    sq_fingerprint_free(sq_fpr);
  12.322 +
  12.323 +    return fpr_canonicalized;
  12.324 +}
  12.325 +
  12.326 +// Splits an OpenPGP user id into its name and email components.  A
  12.327 +// user id looks like:
  12.328 +//
  12.329 +//   Name (comment) <email>
  12.330 +//
  12.331 +// This function takes ownership of user_id!!!
  12.332 +//
  12.333 +// namep and emailp may be NULL if they are not required.
  12.334 +static void user_id_split(char *, char **, char **) __attribute__((nonnull(1)));
  12.335 +static void user_id_split(char *user_id, char **namep, char **emailp)
  12.336 +{
  12.337 +    if (namep)
  12.338 +        *namep = NULL;
  12.339 +    if (emailp)
  12.340 +        *emailp = NULL;
  12.341 +
  12.342 +    char *email = strchr(user_id, '<');
  12.343 +    if (email) {
  12.344 +        // NUL terminate the string here so that user_id now points at
  12.345 +        // most to: "Name (comment)"
  12.346 +        *email = 0;
  12.347 +
  12.348 +        if (emailp && email[1]) {
  12.349 +            email = email + 1;
  12.350 +            char *end = strchr(email, '>');
  12.351 +            if (end) {
  12.352 +                *end = 0;
  12.353 +                *emailp = strdup(email);
  12.354 +            }
  12.355 +        }
  12.356 +    }
  12.357 +
  12.358 +    if (!namep)
  12.359 +        return;
  12.360 +
  12.361 +    char *comment = strchr(user_id, '(');
  12.362 +    if (comment)
  12.363 +        *comment = 0;
  12.364 +
  12.365 +    // Kill any trailing white space.
  12.366 +    for (size_t l = strlen(user_id); l > 0 && user_id[l - 1] == ' '; l --)
  12.367 +        user_id[l - 1] = 0;
  12.368 +
  12.369 +    // Kill any leading whitespace.
  12.370 +    char *start = user_id;
  12.371 +    while (*start == ' ')
  12.372 +        start ++;
  12.373 +    if (start[0])
  12.374 +        *namep = strdup(start);
  12.375 +
  12.376 +    free(user_id);
  12.377 +}
  12.378 +
  12.379 +// step statement and load the tpk and secret.
  12.380 +static PEP_STATUS key_load(PEP_SESSION, sqlite3_stmt *, sq_tpk_t *, int *)
  12.381 +    __attribute__((nonnull(1, 2)));
  12.382 +static PEP_STATUS key_load(PEP_SESSION session, sqlite3_stmt *stmt,
  12.383 +                           sq_tpk_t *tpkp, int *secretp)
  12.384 +{
  12.385 +    PEP_STATUS status = PEP_STATUS_OK;
  12.386 +    int sqlite_result = sqlite3_step(stmt);
  12.387 +    switch (sqlite_result) {
  12.388 +    case SQLITE_ROW:
  12.389 +        if (tpkp) {
  12.390 +            int data_len = sqlite3_column_bytes(stmt, 0);
  12.391 +            const void *data = sqlite3_column_blob(stmt, 0);
  12.392 +
  12.393 +            *tpkp = sq_tpk_from_bytes(session->ctx, data, data_len);
  12.394 +            if (!*tpkp)
  12.395 +                ERROR_OUT(session, PEP_GET_KEY_FAILED, "parsing TPK");
  12.396 +        }
  12.397 +
  12.398 +        if (secretp)
  12.399 +            *secretp = sqlite3_column_int(stmt, 1);
  12.400 +
  12.401 +        break;
  12.402 +    case SQLITE_DONE:
  12.403 +        // Got nothing.
  12.404 +        status = PEP_KEY_NOT_FOUND;
  12.405 +        break;
  12.406 +    default:
  12.407 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR,
  12.408 +                  "stepping: %s", sqlite3_errmsg(session->key_db));
  12.409 +    }
  12.410 +
  12.411 + out:
  12.412 +    T(" -> %s", pep_status_to_string(status));
  12.413 +    return status;
  12.414 +}
  12.415 +
  12.416 +// step statement until exhausted and load the tpks.
  12.417 +static PEP_STATUS key_loadn(PEP_SESSION, sqlite3_stmt *, sq_tpk_t **, int *)
  12.418 +    __attribute__((nonnull));
  12.419 +static PEP_STATUS key_loadn(PEP_SESSION session, sqlite3_stmt *stmt,
  12.420 +                            sq_tpk_t **tpksp, int *tpks_countp)
  12.421 +{
  12.422 +    PEP_STATUS status = PEP_STATUS_OK;
  12.423 +    int tpks_count = 0;
  12.424 +    int tpks_capacity = 8;
  12.425 +    sq_tpk_t *tpks = calloc(tpks_capacity, sizeof(sq_tpk_t));
  12.426 +    if (!tpks)
  12.427 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
  12.428 +
  12.429 +    for (;;) {
  12.430 +        sq_tpk_t tpk = NULL;
  12.431 +        status = key_load(session, stmt, &tpk, NULL);
  12.432 +        if (status == PEP_KEY_NOT_FOUND) {
  12.433 +            status = PEP_STATUS_OK;
  12.434 +            break;
  12.435 +        }
  12.436 +        ERROR_OUT(session, status, "loading TPK");
  12.437 +
  12.438 +        if (tpks_count == tpks_capacity) {
  12.439 +            tpks_capacity *= 2;
  12.440 +            tpks = realloc(tpks, sizeof(tpks[0]) * tpks_capacity);
  12.441 +            if (!tpks)
  12.442 +                ERROR_OUT(session, PEP_OUT_OF_MEMORY, "tpks");
  12.443 +        }
  12.444 +        tpks[tpks_count ++] = tpk;
  12.445 +    }
  12.446 +
  12.447 + out:
  12.448 +    if (status != PEP_STATUS_OK) {
  12.449 +        for (int i = 0; i < tpks_count; i ++)
  12.450 +            sq_tpk_free(tpks[i]);
  12.451 +        free(tpks);
  12.452 +    } else {
  12.453 +        *tpksp = tpks;
  12.454 +        *tpks_countp = tpks_count;
  12.455 +    }
  12.456 +
  12.457 +    T(" -> %s (%d tpks)", pep_status_to_string(status), *tpks_countp);
  12.458 +    return status;
  12.459 +}
  12.460 +
  12.461 +// Returns the TPK identified by the provided fingerprint.
  12.462 +//
  12.463 +// This function only matches on the primary key!
  12.464 +static PEP_STATUS tpk_find(PEP_SESSION, sq_fingerprint_t, int, sq_tpk_t *, int *)
  12.465 +    __attribute__((nonnull(1, 2)));
  12.466 +static PEP_STATUS tpk_find(PEP_SESSION session,
  12.467 +                           sq_fingerprint_t fpr, int private_only,
  12.468 +                           sq_tpk_t *tpk, int *secret)
  12.469 +{
  12.470 +    PEP_STATUS status = PEP_STATUS_OK;
  12.471 +    char *fpr_str = sq_fingerprint_to_hex(fpr);
  12.472 +
  12.473 +    T("(%s, %d)", fpr_str, private_only);
  12.474 +
  12.475 +    sqlite3_stmt *stmt = private_only ? session->sq_sql.tsk_find : session->sq_sql.tpk_find;
  12.476 +    sqlite3_bind_text(stmt, 1, fpr_str, -1, SQLITE_STATIC);
  12.477 +
  12.478 +    status = key_load(session, stmt, tpk, secret);
  12.479 +    ERROR_OUT(session, status, "Looking up %s", fpr_str);
  12.480 +
  12.481 + out:
  12.482 +    sqlite3_reset(stmt);
  12.483 +    T("(%s, %d) -> %s", fpr_str, private_only, pep_status_to_string(status));
  12.484 +    free(fpr_str);
  12.485 +    return status;
  12.486 +}
  12.487 +
  12.488 +// Returns the TPK identified by the provided keyid.
  12.489 +//
  12.490 +// This function matches on both primary keys and subkeys!
  12.491 +//
  12.492 +// Note: There can be multiple TPKs for a given keyid.  This can
  12.493 +// occur, because an encryption subkey can be bound to multiple TPKs.
  12.494 +// Also, it is possible to collide key ids.  If there are multiple key
  12.495 +// ids for a given key, this just returns one of them.
  12.496 +//
  12.497 +// If private_only is set, this will only consider TPKs with some
  12.498 +// secret key material.
  12.499 +static PEP_STATUS tpk_find_by_keyid_hex(PEP_SESSION, const char *, int, sq_tpk_t *, int *)
  12.500 +  __attribute__((nonnull(1, 2)));
  12.501 +static PEP_STATUS tpk_find_by_keyid_hex(
  12.502 +        PEP_SESSION session, const char *keyid_hex, int private_only,
  12.503 +        sq_tpk_t *tpkp, int *secretp)
  12.504 +{
  12.505 +    PEP_STATUS status = PEP_STATUS_OK;
  12.506 +    T("(%s, %d)", keyid_hex, private_only);
  12.507 +
  12.508 +    sqlite3_stmt *stmt
  12.509 +        = private_only ? session->sq_sql.tsk_find_by_keyid : session->sq_sql.tpk_find_by_keyid;
  12.510 +    sqlite3_bind_text(stmt, 1, keyid_hex, -1, SQLITE_STATIC);
  12.511 +
  12.512 +    status = key_load(session, stmt, tpkp, secretp);
  12.513 +    ERROR_OUT(session, status, "Looking up %s", keyid_hex);
  12.514 +
  12.515 + out:
  12.516 +    sqlite3_reset(stmt);
  12.517 +    T("(%s, %d) -> %s", keyid_hex, private_only, pep_status_to_string(status));
  12.518 +    return status;
  12.519 +}
  12.520 +
  12.521 +// See tpk_find_by_keyid_hex.
  12.522 +PEP_STATUS tpk_find_by_keyid(PEP_SESSION, sq_keyid_t, int, sq_tpk_t *, int *)
  12.523 +    __attribute__((nonnull(1, 2)));
  12.524 +PEP_STATUS tpk_find_by_keyid(PEP_SESSION session,
  12.525 +                             sq_keyid_t keyid, int private_only,
  12.526 +                             sq_tpk_t *tpkp, int *secretp)
  12.527 +{
  12.528 +    char *keyid_hex = sq_keyid_to_hex(keyid);
  12.529 +    if (! keyid_hex)
  12.530 +        return PEP_OUT_OF_MEMORY;
  12.531 +    PEP_STATUS status
  12.532 +        = tpk_find_by_keyid_hex(session, keyid_hex, private_only, tpkp, secretp);
  12.533 +    free(keyid_hex);
  12.534 +    return status;
  12.535 +}
  12.536 +
  12.537 +// See tpk_find_by_keyid_hex.
  12.538 +static PEP_STATUS tpk_find_by_fpr(PEP_SESSION, sq_fingerprint_t, int,
  12.539 +                                  sq_tpk_t *, int *)
  12.540 +    __attribute__((nonnull(1, 2)));
  12.541 +static PEP_STATUS tpk_find_by_fpr(
  12.542 +    PEP_SESSION session, sq_fingerprint_t fpr, int private_only,
  12.543 +    sq_tpk_t *tpkp, int *secretp)
  12.544 +{
  12.545 +    sq_keyid_t keyid = sq_fingerprint_to_keyid(fpr);
  12.546 +    if (! keyid)
  12.547 +        return PEP_OUT_OF_MEMORY;
  12.548 +    PEP_STATUS status
  12.549 +        = tpk_find_by_keyid(session, keyid, private_only, tpkp, secretp);
  12.550 +    sq_keyid_free(keyid);
  12.551 +    return status;
  12.552 +}
  12.553 +
  12.554 +// See tpk_find_by_keyid_hex.
  12.555 +static PEP_STATUS tpk_find_by_fpr_hex(PEP_SESSION, const char *, int, sq_tpk_t *, int *secret)
  12.556 +    __attribute__((nonnull(1, 2)));
  12.557 +static PEP_STATUS tpk_find_by_fpr_hex(
  12.558 +    PEP_SESSION session, const char *fpr, int private_only,
  12.559 +    sq_tpk_t *tpkp, int *secretp)
  12.560 +{
  12.561 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
  12.562 +    if (! sq_fpr)
  12.563 +        return PEP_OUT_OF_MEMORY;
  12.564 +    PEP_STATUS status
  12.565 +        = tpk_find_by_fpr(session, sq_fpr, private_only, tpkp, secretp);
  12.566 +    sq_fingerprint_free(sq_fpr);
  12.567 +    return status;
  12.568 +}
  12.569 +
  12.570 +// Returns all known TPKs.
  12.571 +static PEP_STATUS tpk_all(PEP_SESSION, int, sq_tpk_t **, int *) __attribute__((nonnull));
  12.572 +static PEP_STATUS tpk_all(PEP_SESSION session, int private_only,
  12.573 +                          sq_tpk_t **tpksp, int *tpks_countp) {
  12.574 +    PEP_STATUS status = PEP_STATUS_OK;
  12.575 +    sqlite3_stmt *stmt = private_only ? session->sq_sql.tsk_all : session->sq_sql.tpk_all;
  12.576 +    status = key_loadn(session, stmt, tpksp, tpks_countp);
  12.577 +    ERROR_OUT(session, status, "loading TPKs");
  12.578 + out:
  12.579 +    sqlite3_reset(stmt);
  12.580 +    return status;
  12.581 +}
  12.582 +
  12.583 +// Returns keys that have a user id that matches the specified pattern.
  12.584 +//
  12.585 +// The keys returned must be freed using sq_tpk_free.
  12.586 +static PEP_STATUS tpk_find_by_email(PEP_SESSION, const char *, int, sq_tpk_t **, int *)
  12.587 +    __attribute__((nonnull));
  12.588 +static PEP_STATUS tpk_find_by_email(PEP_SESSION session,
  12.589 +                                    const char *pattern, int private_only,
  12.590 +                                    sq_tpk_t **tpksp, int *countp)
  12.591 +{
  12.592 +    PEP_STATUS status = PEP_STATUS_OK;
  12.593 +    T("(%s)", pattern);
  12.594 +
  12.595 +    sqlite3_stmt *stmt
  12.596 +        = private_only ? session->sq_sql.tsk_find_by_email : session->sq_sql.tpk_find_by_email;
  12.597 +    sqlite3_bind_text(stmt, 1, pattern, -1, SQLITE_STATIC);
  12.598 +
  12.599 +    status = key_loadn(session, stmt, tpksp, countp);
  12.600 +    ERROR_OUT(session, status, "Searching for '%s'", pattern);
  12.601 +
  12.602 + out:
  12.603 +    sqlite3_reset(stmt);
  12.604 +    T("(%s) -> %s (%d results)", pattern, pep_status_to_string(status), *countp);
  12.605 +    return status;
  12.606 +}
  12.607 +
  12.608 +
  12.609 +// Saves the specified TPK.
  12.610 +//
  12.611 +// This function takes ownership of TPK.
  12.612 +static PEP_STATUS tpk_save(PEP_SESSION, sq_tpk_t, identity_list **)
  12.613 +    __attribute__((nonnull(1, 2)));
  12.614 +static PEP_STATUS tpk_save(PEP_SESSION session, sq_tpk_t tpk,
  12.615 +                           identity_list **private_idents)
  12.616 +{
  12.617 +    PEP_STATUS status = PEP_STATUS_OK;
  12.618 +    sq_fingerprint_t sq_fpr = NULL;
  12.619 +    char *fpr = NULL;
  12.620 +    void *tsk_buffer = NULL;
  12.621 +    size_t tsk_buffer_len = 0;
  12.622 +    int tried_commit = 0;
  12.623 +    sq_tpk_key_iter_t key_iter = NULL;
  12.624 +    sq_user_id_binding_iter_t user_id_iter = NULL;
  12.625 +
  12.626 +    sq_fpr = sq_tpk_fingerprint(tpk);
  12.627 +    fpr = sq_fingerprint_to_hex(sq_fpr);
  12.628 +    T("(%s, private_idents: %s)", fpr, private_idents ? "yes" : "no");
  12.629 +
  12.630 +    // Merge any existing data into TPK.
  12.631 +    sq_tpk_t current = NULL;
  12.632 +    status = tpk_find(session, sq_fpr, false, &current, NULL);
  12.633 +    if (status == PEP_KEY_NOT_FOUND)
  12.634 +        status = PEP_STATUS_OK;
  12.635 +    else
  12.636 +        ERROR_OUT(session, status, "Looking up %s", fpr);
  12.637 +    if (current)
  12.638 +        tpk = sq_tpk_merge(session->ctx, tpk, current);
  12.639 +
  12.640 +    int is_tsk = sq_tpk_is_tsk(tpk);
  12.641 +
  12.642 +    // Serialize it.
  12.643 +    sq_writer_t writer = sq_writer_alloc(&tsk_buffer, &tsk_buffer_len);
  12.644 +    if (! writer)
  12.645 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
  12.646 +
  12.647 +    sq_status_t sq_status;
  12.648 +    sq_tsk_t tsk = sq_tpk_into_tsk(tpk);
  12.649 +    sq_status = sq_tsk_serialize(session->ctx, tsk, writer);
  12.650 +    tpk = sq_tsk_into_tpk(tsk);
  12.651 +    //sq_writer_free(writer);
  12.652 +    if (sq_status != 0)
  12.653 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Serializing TPK");
  12.654 +
  12.655 +
  12.656 +    // Insert the TSK into the DB.
  12.657 +    sqlite3_stmt *stmt = session->sq_sql.begin_transaction;
  12.658 +    int sqlite_result = sqlite3_step(stmt);
  12.659 +    sqlite3_reset(stmt);
  12.660 +    if (sqlite_result != SQLITE_DONE)
  12.661 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR,
  12.662 +                  "begin transaction failed: %s",
  12.663 +                  sqlite3_errmsg(session->key_db));
  12.664 +
  12.665 +    stmt = session->sq_sql.tpk_save_insert_primary;
  12.666 +    sqlite3_bind_text(stmt, 1, fpr, -1, SQLITE_STATIC);
  12.667 +    sqlite3_bind_int(stmt, 2, is_tsk);
  12.668 +    sqlite3_bind_blob(stmt, 3, tsk_buffer, tsk_buffer_len, SQLITE_STATIC);
  12.669 +
  12.670 +    sqlite_result = sqlite3_step(stmt);
  12.671 +    sqlite3_reset(stmt);
  12.672 +    if (sqlite_result != SQLITE_DONE)
  12.673 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR,
  12.674 +                  "Saving TPK: %s", sqlite3_errmsg(session->key_db));
  12.675 +
  12.676 +    // Insert the "subkeys" (the primary key and the subkeys).
  12.677 +    stmt = session->sq_sql.tpk_save_insert_subkeys;
  12.678 +    key_iter = sq_tpk_key_iter(tpk);
  12.679 +    sq_p_key_t key;
  12.680 +    while ((key = sq_tpk_key_iter_next(key_iter, NULL, NULL))) {
  12.681 +        sq_keyid_t keyid = sq_p_key_keyid(key);
  12.682 +        char *keyid_hex = sq_keyid_to_hex(keyid);
  12.683 +        sqlite3_bind_text(stmt, 1, keyid_hex, -1, SQLITE_STATIC);
  12.684 +        sqlite3_bind_text(stmt, 2, fpr, -1, SQLITE_STATIC);
  12.685 +
  12.686 +        sqlite_result = sqlite3_step(stmt);
  12.687 +        sqlite3_reset(stmt);
  12.688 +        free(keyid_hex);
  12.689 +        sq_keyid_free(keyid);
  12.690 +        if (sqlite_result != SQLITE_DONE) {
  12.691 +            sq_tpk_key_iter_free(key_iter);
  12.692 +            ERROR_OUT(session, PEP_UNKNOWN_ERROR,
  12.693 +                      "Updating subkeys: %s", sqlite3_errmsg(session->key_db));
  12.694 +        }
  12.695 +    }
  12.696 +    sq_tpk_key_iter_free(key_iter);
  12.697 +    key_iter = NULL;
  12.698 +
  12.699 +    // Insert the "userids".
  12.700 +    stmt = session->sq_sql.tpk_save_insert_userids;
  12.701 +    user_id_iter = sq_tpk_user_id_binding_iter(tpk);
  12.702 +    sq_user_id_binding_t binding;
  12.703 +    int first = 1;
  12.704 +    while ((binding = sq_user_id_binding_iter_next(user_id_iter))) {
  12.705 +        char *user_id = sq_user_id_binding_user_id(binding);
  12.706 +        if (!user_id || !*user_id)
  12.707 +            continue;
  12.708 +
  12.709 +        // Ignore bindings with a self-revocation certificate, but no
  12.710 +        // self-signature.
  12.711 +        if (!sq_user_id_binding_selfsig(binding)) {
  12.712 +            free(user_id);
  12.713 +            continue;
  12.714 +        }
  12.715 +
  12.716 +        char *name, *email;
  12.717 +        user_id_split(user_id, &name, &email); /* user_id is comsumed.  */
  12.718 +        // XXX: Correctly clean up name and email on error...
  12.719 +
  12.720 +        if (email) {
  12.721 +            T("  userid: %s", email);
  12.722 +
  12.723 +            sqlite3_bind_text(stmt, 1, email, -1, SQLITE_STATIC);
  12.724 +            sqlite3_bind_text(stmt, 2, fpr, -1, SQLITE_STATIC);
  12.725 +
  12.726 +            sqlite_result = sqlite3_step(stmt);
  12.727 +            sqlite3_reset(stmt);
  12.728 +
  12.729 +            if (sqlite_result != SQLITE_DONE) {
  12.730 +                sq_user_id_binding_iter_free(user_id_iter);
  12.731 +                free(name);
  12.732 +                ERROR_OUT(session, PEP_UNKNOWN_ERROR,
  12.733 +                          "Updating userids: %s", sqlite3_errmsg(session->key_db));
  12.734 +            }
  12.735 +        }
  12.736 +
  12.737 +        if (first && private_idents && is_tsk) {
  12.738 +            first = 0;
  12.739 +
  12.740 +            // Create an identity for the primary user id.
  12.741 +            pEp_identity *ident = new_identity(email, fpr, NULL, name);
  12.742 +            if (ident == NULL)
  12.743 +                ERROR_OUT(session, PEP_OUT_OF_MEMORY, "new_identity");
  12.744 +
  12.745 +            *private_idents = identity_list_add(*private_idents, ident);
  12.746 +            if (*private_idents == NULL)
  12.747 +                ERROR_OUT(session, PEP_OUT_OF_MEMORY, "identity_list_add");
  12.748 +        }
  12.749 +        free(email);
  12.750 +        free(name);
  12.751 +
  12.752 +    }
  12.753 +    sq_user_id_binding_iter_free(user_id_iter);
  12.754 +    user_id_iter = NULL;
  12.755 +
  12.756 + out:
  12.757 +    // Prevent ERROR_OUT from causing an infinite loop.
  12.758 +    if (! tried_commit) {
  12.759 +        tried_commit = 1;
  12.760 +        stmt = status == PEP_STATUS_OK
  12.761 +            ? session->sq_sql.commit_transaction
  12.762 +            : session->sq_sql.rollback_transaction;
  12.763 +        int sqlite_result = sqlite3_step(stmt);
  12.764 +        sqlite3_reset(stmt);
  12.765 +        if (sqlite_result != SQLITE_DONE)
  12.766 +            ERROR_OUT(session, PEP_UNKNOWN_ERROR,
  12.767 +                      status == PEP_STATUS_OK
  12.768 +                      ? "commit failed: %s" : "rollback failed: %s",
  12.769 +                      sqlite3_errmsg(session->key_db));
  12.770 +    }
  12.771 +
  12.772 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
  12.773 +
  12.774 +    if (user_id_iter)
  12.775 +        sq_user_id_binding_iter_free(user_id_iter);
  12.776 +    if (key_iter)
  12.777 +        sq_tpk_key_iter_free(key_iter);
  12.778 +    if (stmt)
  12.779 +      sqlite3_reset(stmt);
  12.780 +    free(tsk_buffer);
  12.781 +    if (tpk)
  12.782 +        sq_tpk_free(tpk);
  12.783 +    free(fpr);
  12.784 +    sq_fingerprint_free(sq_fpr);
  12.785 +
  12.786 +    return status;
  12.787 +}
  12.788 +
  12.789 +struct decrypt_cookie {
  12.790 +    PEP_SESSION session;
  12.791 +    int get_secret_keys_called;
  12.792 +    stringlist_t *recipient_keylist;
  12.793 +    stringlist_t *signer_keylist;
  12.794 +    int good_checksums;
  12.795 +    int missing_keys;
  12.796 +    int bad_checksums;
  12.797 +    int decrypted;
  12.798 +};
  12.799 +
  12.800 +static sq_status_t
  12.801 +get_public_keys_cb(void *cookie_raw,
  12.802 +                   sq_keyid_t *keyids, size_t keyids_len,
  12.803 +                   sq_tpk_t **tpks, size_t *tpk_len,
  12.804 +                   void (**our_free)(void *))
  12.805 +{
  12.806 +    struct decrypt_cookie *cookie = cookie_raw;
  12.807 +    PEP_SESSION session = cookie->session;
  12.808 +
  12.809 +    *tpks = calloc(keyids_len, sizeof(*tpks));
  12.810 +    if (!*tpks)
  12.811 +        return SQ_STATUS_UNKNOWN_ERROR;
  12.812 +    *our_free = free;
  12.813 +
  12.814 +    int i, j;
  12.815 +    j = 0;
  12.816 +    for (i = 0; i < keyids_len; i ++) {
  12.817 +        sq_tpk_t tpk = NULL;
  12.818 +        sq_status_t status
  12.819 +            = tpk_find_by_keyid(session, keyids[i], false, &tpk, NULL);
  12.820 +        if (status == SQ_STATUS_SUCCESS)
  12.821 +            (*tpks)[j ++] = tpk;
  12.822 +    }
  12.823 +    *tpk_len = j;
  12.824 +    return SQ_STATUS_SUCCESS;
  12.825 +}
  12.826 +
  12.827 +static sq_status_t
  12.828 +get_secret_keys_cb(void *cookie_opaque,
  12.829 +                   sq_pkesk_t *pkesks, size_t pkesk_count,
  12.830 +                   sq_skesk_t *skesks, size_t skesk_count,
  12.831 +                   sq_secret_t *secret)
  12.832 +{
  12.833 +    struct decrypt_cookie *cookie = cookie_opaque;
  12.834 +    PEP_SESSION session = cookie->session;
  12.835 +    sq_tpk_t *tsks = NULL;
  12.836 +    int tsks_count = 0;
  12.837 +    int wildcards = 0;
  12.838 +
  12.839 +    if (cookie->get_secret_keys_called)
  12.840 +        // Prevent iterations, which isn't needed since we don't
  12.841 +        // support SKESKs.
  12.842 +        return SQ_STATUS_UNKNOWN_ERROR;
  12.843 +    cookie->get_secret_keys_called = 1;
  12.844 +
  12.845 +    T("%zd PKESKs", pkesk_count);
  12.846 +
  12.847 +    for (int i = 0; i < pkesk_count; i ++) {
  12.848 +        sq_pkesk_t pkesk = pkesks[i];
  12.849 +        sq_keyid_t keyid = sq_pkesk_recipient(pkesk); /* Reference. */
  12.850 +        char *keyid_str = sq_keyid_to_hex(keyid);
  12.851 +        sq_tpk_key_iter_t key_iter = NULL;
  12.852 +
  12.853 +        T("Considering PKESK for %s", keyid_str);
  12.854 +
  12.855 +        if (strcmp(keyid_str, "0000000000000000") == 0) {
  12.856 +            // Initially ignore wildcards.
  12.857 +            wildcards = 1;
  12.858 +            goto eol;
  12.859 +        }
  12.860 +
  12.861 +        // Collect the recipients.  Note: we must return the primary
  12.862 +        // key's fingerprint.
  12.863 +        sq_tpk_t tpk = NULL;
  12.864 +        int is_tsk = 0;
  12.865 +        if (tpk_find_by_keyid(session, keyid, false, &tpk, &is_tsk) != PEP_STATUS_OK)
  12.866 +            goto eol;
  12.867 +
  12.868 +        sq_fingerprint_t fp = sq_tpk_fingerprint(tpk);
  12.869 +        char *fp_string = sq_fingerprint_to_hex(fp);
  12.870 +        stringlist_add_unique(cookie->recipient_keylist, fp_string);
  12.871 +        free(fp_string);
  12.872 +        sq_fingerprint_free(fp);
  12.873 +
  12.874 +        if (cookie->decrypted)
  12.875 +            goto eol;
  12.876 +
  12.877 +        // See if we have the secret key.
  12.878 +        assert(is_tsk == sq_tpk_is_tsk(tpk));
  12.879 +        if (! is_tsk)
  12.880 +            goto eol;
  12.881 +
  12.882 +        key_iter = sq_tpk_key_iter(tpk);
  12.883 +        sq_p_key_t key;
  12.884 +        while ((key = sq_tpk_key_iter_next(key_iter, NULL, NULL))) {
  12.885 +            sq_keyid_t this_keyid = sq_p_key_keyid(key);
  12.886 +            char *this_keyid_hex = sq_keyid_to_hex(this_keyid);
  12.887 +            sq_keyid_free(this_keyid);
  12.888 +
  12.889 +            int match = strcmp(keyid_str, this_keyid_hex) == 0;
  12.890 +            free(this_keyid_hex);
  12.891 +            if (match)
  12.892 +                break;
  12.893 +        }
  12.894 +
  12.895 +        if (key == NULL) {
  12.896 +            assert(!"Inconsistent DB: key doesn't contain a subkey with keyid!");
  12.897 +            goto eol;
  12.898 +        }
  12.899 +
  12.900 +        uint8_t algo;
  12.901 +        uint8_t session_key[1024];
  12.902 +        size_t session_key_len = sizeof(session_key);
  12.903 +        if (sq_pkesk_decrypt(cookie->session->ctx,
  12.904 +                             pkesk, key, &algo,
  12.905 +                             session_key, &session_key_len) != 0) {
  12.906 +            DUMP_ERR(session, PEP_UNKNOWN_ERROR, "sq_pkesk_decrypt");
  12.907 +            goto eol;
  12.908 +        }
  12.909 +
  12.910 +        T("Decrypted PKESK for %s", keyid_str);
  12.911 +
  12.912 +        *secret = sq_secret_cached(algo, session_key, session_key_len);
  12.913 +        cookie->decrypted = 1;
  12.914 +
  12.915 +    eol:
  12.916 +        free(keyid_str);
  12.917 +        if (key_iter)
  12.918 +            sq_tpk_key_iter_free(key_iter);
  12.919 +        if (tpk)
  12.920 +            sq_tpk_free(tpk);
  12.921 +    }
  12.922 +
  12.923 +    // Consider wildcard recipients.
  12.924 +    if (wildcards) for (int i = 0; i < pkesk_count && !cookie->decrypted; i ++) {
  12.925 +        sq_pkesk_t pkesk = pkesks[i];
  12.926 +        sq_keyid_t keyid = sq_pkesk_recipient(pkesk); /* Reference. */
  12.927 +        char *keyid_str = sq_keyid_to_hex(keyid);
  12.928 +        sq_tpk_key_iter_t key_iter = NULL;
  12.929 +
  12.930 +        if (strcmp(keyid_str, "0000000000000000") != 0)
  12.931 +            goto eol2;
  12.932 +
  12.933 +        if (!tsks) {
  12.934 +            if (tpk_all(session, true, &tsks, &tsks_count) != PEP_STATUS_OK) {
  12.935 +                DUMP_ERR(session, PEP_UNKNOWN_ERROR, "Getting all tsks");
  12.936 +            }
  12.937 +        }
  12.938 +
  12.939 +        for (int j = 0; j < tsks_count; j ++) {
  12.940 +            sq_tpk_t tsk = tsks[j];
  12.941 +
  12.942 +            key_iter = sq_tpk_key_iter(tsk);
  12.943 +            sq_p_key_t key;
  12.944 +            sq_signature_t selfsig;
  12.945 +            while ((key = sq_tpk_key_iter_next(key_iter, &selfsig, NULL))) {
  12.946 +                if (! (sq_signature_can_encrypt_at_rest(selfsig)
  12.947 +                       || sq_signature_can_encrypt_for_transport(selfsig)))
  12.948 +                    continue;
  12.949 +
  12.950 +                // Note: for decryption to appear to succeed, we must
  12.951 +                // get a valid algorithm (8 of 256 values) and a
  12.952 +                // 16-bit checksum must match.  Thus, we have about a
  12.953 +                // 1 in 2**21 chance of having a false positive here.
  12.954 +                uint8_t algo;
  12.955 +                uint8_t session_key[1024];
  12.956 +                size_t session_key_len = sizeof(session_key);
  12.957 +                if (sq_pkesk_decrypt(cookie->session->ctx, pkesk, key,
  12.958 +                                     &algo, session_key, &session_key_len))
  12.959 +                    continue;
  12.960 +
  12.961 +                // Add it to the recipient list.
  12.962 +                sq_fingerprint_t fp = sq_tpk_fingerprint(tsk);
  12.963 +                char *fp_string = sq_fingerprint_to_hex(fp);
  12.964 +                T("wildcard recipient appears to be %s", fp_string);
  12.965 +                stringlist_add_unique(cookie->recipient_keylist, fp_string);
  12.966 +                free(fp_string);
  12.967 +                sq_fingerprint_free(fp);
  12.968 +
  12.969 +                *secret = sq_secret_cached(algo, session_key, session_key_len);
  12.970 +                cookie->decrypted = 1;
  12.971 +            }
  12.972 +
  12.973 +            sq_tpk_key_iter_free(key_iter);
  12.974 +            key_iter = NULL;
  12.975 +        }
  12.976 +    eol2:
  12.977 +        free(keyid_str);
  12.978 +        if (key_iter)
  12.979 +            sq_tpk_key_iter_free(key_iter);
  12.980 +    }
  12.981 +
  12.982 +    if (tsks) {
  12.983 +        for (int i = 0; i < tsks_count; i ++)
  12.984 +            sq_tpk_free(tsks[i]);
  12.985 +        free(tsks);
  12.986 +    }
  12.987 +
  12.988 +    return cookie->decrypted ? SQ_STATUS_SUCCESS : SQ_STATUS_UNKNOWN_ERROR;
  12.989 +}
  12.990 +
  12.991 +static sq_status_t
  12.992 +check_signatures_cb(void *cookie_opaque,
  12.993 +                   sq_verification_results_t results, size_t levels)
  12.994 +{
  12.995 +    struct decrypt_cookie *cookie = cookie_opaque;
  12.996 +    PEP_SESSION session = cookie->session;
  12.997 +
  12.998 +    int level;
  12.999 +    for (level = 0; level < levels; level ++) {
 12.1000 +        sq_verification_result_t *vrs;
 12.1001 +        size_t vr_count;
 12.1002 +        sq_verification_results_at_level(results, level, &vrs, &vr_count);
 12.1003 +
 12.1004 +        int i;
 12.1005 +        for (i = 0; i < vr_count; i ++) {
 12.1006 +            sq_tpk_t tpk = NULL;
 12.1007 +            sq_verification_result_code_t code
 12.1008 +                = sq_verification_result_code(vrs[i]);
 12.1009 +
 12.1010 +            if (code == SQ_VERIFICATION_RESULT_CODE_BAD_CHECKSUM) {
 12.1011 +                cookie->bad_checksums ++;
 12.1012 +                continue;
 12.1013 +            }
 12.1014 +            if (code == SQ_VERIFICATION_RESULT_CODE_MISSING_KEY) {
 12.1015 +                // No key, nothing we can do.
 12.1016 +                cookie->missing_keys ++;
 12.1017 +                continue;
 12.1018 +            }
 12.1019 +
 12.1020 +            // We need to add the fingerprint of the primary key to
 12.1021 +            // cookie->signer_keylist.
 12.1022 +            sq_signature_t sig = sq_verification_result_signature(vrs[i]);
 12.1023 +
 12.1024 +            // First try looking up by the TPK using the
 12.1025 +            // IssuerFingerprint subpacket.
 12.1026 +            sq_fingerprint_t issuer_fp = sq_signature_issuer_fingerprint(sig);
 12.1027 +            if (issuer_fp) {
 12.1028 +                sq_keyid_t issuer = sq_fingerprint_to_keyid(issuer_fp);
 12.1029 +                if (tpk_find_by_keyid(session, issuer, false, &tpk, NULL) != PEP_STATUS_OK)
 12.1030 +                    ; // Soft error.  Ignore.
 12.1031 +                sq_keyid_free(issuer);
 12.1032 +                sq_fingerprint_free(issuer_fp);
 12.1033 +            }
 12.1034 +
 12.1035 +            // If that is not available, try using the Issuer subpacket.
 12.1036 +            if (!tpk) {
 12.1037 +                sq_keyid_t issuer = sq_signature_issuer(sig);
 12.1038 +                if (issuer) {
 12.1039 +                    if (tpk_find_by_keyid(session, issuer, false, &tpk, NULL) != PEP_STATUS_OK)
 12.1040 +                        ; // Soft error.  Ignore.
 12.1041 +                }
 12.1042 +                sq_keyid_free(issuer);
 12.1043 +            }
 12.1044 +
 12.1045 +            if (tpk) {
 12.1046 +                // Ok, we have a TPK.
 12.1047 +                sq_fingerprint_t fp = sq_tpk_fingerprint(tpk);
 12.1048 +                char *fp_str = sq_fingerprint_to_hex(fp);
 12.1049 +                stringlist_add_unique(cookie->signer_keylist, fp_str);
 12.1050 +
 12.1051 +                // XXX: Check that the TPK and the key used to make
 12.1052 +                // the signature and the signature itself are alive
 12.1053 +                // and not revoked.  Revoked =>
 12.1054 +                // PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH; Expired key
 12.1055 +                // or sig => PEP_DECRYPTED.
 12.1056 +                cookie->good_checksums ++;
 12.1057 +
 12.1058 +                free(fp_str);
 12.1059 +                sq_fingerprint_free(fp);
 12.1060 +                sq_tpk_free(tpk);
 12.1061 +            } else {
 12.1062 +                // If we get
 12.1063 +                // SQ_VERIFICATION_RESULT_CODE_GOOD_CHECKSUM, then the
 12.1064 +                // TPK should be available.  But, another process
 12.1065 +                // could have deleted the key from the store in the
 12.1066 +                // mean time, so be tolerant.
 12.1067 +                cookie->missing_keys ++;
 12.1068 +            }
 12.1069 +        }
 12.1070 +    }
 12.1071 +
 12.1072 +    return SQ_STATUS_SUCCESS;
 12.1073 +}
 12.1074 +
 12.1075 +PEP_STATUS pgp_decrypt_and_verify(
 12.1076 +    PEP_SESSION session, const char *ctext, size_t csize,
 12.1077 +    const char *dsigtext, size_t dsigsize,
 12.1078 +    char **ptext, size_t *psize, stringlist_t **keylist,
 12.1079 +    char** filename_ptr)
 12.1080 +{
 12.1081 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1082 +    struct decrypt_cookie cookie = { session, 0, NULL, NULL, 0, 0, 0, };
 12.1083 +    sq_reader_t reader = NULL;
 12.1084 +    sq_writer_t writer = NULL;
 12.1085 +    *ptext = NULL;
 12.1086 +    *psize = 0;
 12.1087 +
 12.1088 +    // XXX: We don't yet handle detached signatures over encrypted
 12.1089 +    // messages.
 12.1090 +    assert(!dsigtext);
 12.1091 +
 12.1092 +    cookie.recipient_keylist = new_stringlist(NULL);
 12.1093 +    if (!cookie.recipient_keylist)
 12.1094 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "recipient_keylist");
 12.1095 +
 12.1096 +    cookie.signer_keylist = new_stringlist(NULL);
 12.1097 +    if (!cookie.signer_keylist)
 12.1098 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "signer_keylist");
 12.1099 +
 12.1100 +    reader = sq_reader_from_bytes((const uint8_t *) ctext, csize);
 12.1101 +    if (! reader)
 12.1102 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "Creating reader");
 12.1103 +
 12.1104 +    writer = sq_writer_alloc((void **) ptext, psize);
 12.1105 +    if (! writer)
 12.1106 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Creating writer");
 12.1107 +
 12.1108 +    sq_status_t sq_status = sq_decrypt(session->ctx, reader, writer,
 12.1109 +                                       get_public_keys_cb, get_secret_keys_cb,
 12.1110 +                                       check_signatures_cb, &cookie);
 12.1111 +    if (sq_status)
 12.1112 +        ERROR_OUT(session, PEP_DECRYPT_NO_KEY, "sq_decrypt");
 12.1113 +
 12.1114 +    if (! cookie.decrypted)
 12.1115 +        ERROR_OUT(session, PEP_DECRYPT_NO_KEY, "Decryption failed");
 12.1116 +
 12.1117 +    // Add a terminating NUL for naive users
 12.1118 +    void *t = realloc(*ptext, *psize + 1);
 12.1119 +    if (! t)
 12.1120 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
 12.1121 +    *ptext = t;
 12.1122 +    (*ptext)[*psize] = 0;
 12.1123 +
 12.1124 +    if (! cookie.signer_keylist) {
 12.1125 +        cookie.signer_keylist = new_stringlist("");
 12.1126 +        if (! cookie.signer_keylist)
 12.1127 +            ERROR_OUT(session, PEP_OUT_OF_MEMORY, "cookie.signer_keylist");
 12.1128 +    }
 12.1129 +    if (!cookie.signer_keylist->value)
 12.1130 +        stringlist_add(cookie.signer_keylist, "");
 12.1131 +
 12.1132 +    *keylist = cookie.signer_keylist;
 12.1133 +    stringlist_append(*keylist, cookie.recipient_keylist);
 12.1134 +
 12.1135 + out:
 12.1136 +    if (status == PEP_STATUS_OK) {
 12.1137 +        if (cookie.bad_checksums) {
 12.1138 +            // If there are any bad signatures, fail.
 12.1139 +            status = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
 12.1140 +        } else if (cookie.good_checksums) {
 12.1141 +            // If there is at least one signature that we can verify,
 12.1142 +            // succeed.
 12.1143 +            status = PEP_DECRYPTED_AND_VERIFIED;
 12.1144 +        } else {
 12.1145 +            // We couldn't verify any signatures (possibly because we
 12.1146 +            // don't have the keys).
 12.1147 +            status = PEP_DECRYPTED;
 12.1148 +        }
 12.1149 +    } else {
 12.1150 +        free_stringlist(cookie.recipient_keylist);
 12.1151 +        free_stringlist(cookie.signer_keylist);
 12.1152 +        free(*ptext);
 12.1153 +    }
 12.1154 +
 12.1155 +    if (reader)
 12.1156 +        sq_reader_free(reader);
 12.1157 +    if (writer)
 12.1158 +        sq_writer_free(writer);
 12.1159 +
 12.1160 +    T("-> %s", pep_status_to_string(status));
 12.1161 +    return status;
 12.1162 +}
 12.1163 +
 12.1164 +PEP_STATUS pgp_verify_text(
 12.1165 +    PEP_SESSION session, const char *text, size_t size,
 12.1166 +    const char *signature, size_t sig_size, stringlist_t **keylist)
 12.1167 +{
 12.1168 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1169 +    struct decrypt_cookie cookie = { session, 0, NULL, NULL, 0, 0, 0, };
 12.1170 +    sq_reader_t reader = NULL;
 12.1171 +    sq_reader_t dsig_reader = NULL;
 12.1172 +
 12.1173 +    if (size == 0 || sig_size == 0)
 12.1174 +        return PEP_DECRYPT_WRONG_FORMAT;
 12.1175 +
 12.1176 +    cookie.recipient_keylist = new_stringlist(NULL);
 12.1177 +    if (!cookie.recipient_keylist)
 12.1178 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
 12.1179 +
 12.1180 +    cookie.signer_keylist = new_stringlist(NULL);
 12.1181 +    if (!cookie.signer_keylist)
 12.1182 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
 12.1183 +
 12.1184 +    reader = sq_reader_from_bytes((const uint8_t *) text, size);
 12.1185 +    if (! reader)
 12.1186 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "Creating reader");
 12.1187 +
 12.1188 +    dsig_reader = NULL;
 12.1189 +    if (signature) {
 12.1190 +        dsig_reader = sq_reader_from_bytes((uint8_t *) signature, sig_size);
 12.1191 +        if (! dsig_reader)
 12.1192 +            ERROR_OUT(session, PEP_OUT_OF_MEMORY, "Creating signature reader");
 12.1193 +    }
 12.1194 +
 12.1195 +    if (sq_verify(session->ctx, reader, dsig_reader, /* output */ NULL,
 12.1196 +                  get_public_keys_cb, check_signatures_cb, &cookie))
 12.1197 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "sq_verify");
 12.1198 +
 12.1199 +    if (! cookie.signer_keylist) {
 12.1200 +        cookie.signer_keylist = new_stringlist("");
 12.1201 +        if (! cookie.signer_keylist)
 12.1202 +            ERROR_OUT(session, PEP_OUT_OF_MEMORY, "cookie.signer_keylist");
 12.1203 +    }
 12.1204 +    if (!cookie.signer_keylist->value)
 12.1205 +        stringlist_add(cookie.signer_keylist, "");
 12.1206 +
 12.1207 +    *keylist = cookie.signer_keylist;
 12.1208 +    stringlist_append(*keylist, cookie.recipient_keylist);
 12.1209 +
 12.1210 + out:
 12.1211 +    if (status == PEP_STATUS_OK) {
 12.1212 +        if (cookie.bad_checksums) {
 12.1213 +            // If there are any bad signatures, fail.
 12.1214 +            status = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
 12.1215 +        } else if (cookie.good_checksums) {
 12.1216 +            // If there is at least one signature that we can verify,
 12.1217 +            // succeed.
 12.1218 +            status = PEP_VERIFIED;
 12.1219 +        } else {
 12.1220 +            // We couldn't verify any signatures (possibly because we
 12.1221 +            // don't have the keys).
 12.1222 +            status = PEP_UNENCRYPTED;
 12.1223 +        }
 12.1224 +    } else {
 12.1225 +        free_stringlist(cookie.recipient_keylist);
 12.1226 +        free_stringlist(cookie.signer_keylist);
 12.1227 +    }
 12.1228 +
 12.1229 +    if (reader)
 12.1230 +        sq_reader_free(reader);
 12.1231 +    if (dsig_reader)
 12.1232 +        sq_reader_free(dsig_reader);
 12.1233 +
 12.1234 +    T("-> %s", pep_status_to_string(status));
 12.1235 +    return status;
 12.1236 +}
 12.1237 +
 12.1238 +
 12.1239 +PEP_STATUS pgp_sign_only(
 12.1240 +    PEP_SESSION session, const char* fpr, const char *ptext,
 12.1241 +    size_t psize, char **stext, size_t *ssize)
 12.1242 +{
 12.1243 +    assert(session);
 12.1244 +    assert(fpr && fpr[0]);
 12.1245 +    assert(ptext);
 12.1246 +    assert(psize);
 12.1247 +    assert(stext);
 12.1248 +    assert(ssize);
 12.1249 +
 12.1250 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1251 +    sq_tpk_t signer = NULL;
 12.1252 +    sq_writer_stack_t ws = NULL;
 12.1253 +
 12.1254 +    status = tpk_find_by_fpr_hex(session, fpr, true, &signer, NULL);
 12.1255 +    ERROR_OUT(session, status, "Looking up key '%s'", fpr);
 12.1256 +
 12.1257 +    sq_writer_t writer = sq_writer_alloc((void **) stext, ssize);
 12.1258 +    writer = sq_armor_writer_new(session->ctx, writer,
 12.1259 +                                 SQ_ARMOR_KIND_MESSAGE, NULL, 0);
 12.1260 +    if (!writer)
 12.1261 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Setting up armor writer");
 12.1262 +
 12.1263 +    ws = sq_writer_stack_message(writer);
 12.1264 +
 12.1265 +    ws = sq_signer_new_detached(session->ctx, ws, &signer, 1);
 12.1266 +    if (!ws)
 12.1267 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Setting up signer");
 12.1268 +
 12.1269 +    sq_status_t write_status =
 12.1270 +        sq_writer_stack_write_all (session->ctx, ws,
 12.1271 +                                   (uint8_t *) ptext, psize);
 12.1272 +    if (write_status != 0)
 12.1273 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Encrypting message");
 12.1274 +
 12.1275 +    // Add a terminating NUL for naive users
 12.1276 +    void *t = realloc(*stext, *ssize + 1);
 12.1277 +    if (! t)
 12.1278 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
 12.1279 +    *stext = t;
 12.1280 +    (*stext)[*ssize] = 0;
 12.1281 +
 12.1282 + out:
 12.1283 +    if (ws) {
 12.1284 +        sq_status_t sq_status = sq_writer_stack_finalize (session->ctx, ws);
 12.1285 +        ws = NULL;
 12.1286 +        if (sq_status != 0)
 12.1287 +            ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Flushing writer");
 12.1288 +    }
 12.1289 +
 12.1290 +    if (signer)
 12.1291 +        sq_tpk_free(signer);
 12.1292 +
 12.1293 +    T("(%s)-> %s", fpr, pep_status_to_string(status));
 12.1294 +    return status;
 12.1295 +}
 12.1296 +
 12.1297 +static PEP_STATUS pgp_encrypt_sign_optional(
 12.1298 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
 12.1299 +    size_t psize, char **ctext, size_t *csize, bool sign)
 12.1300 +{
 12.1301 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1302 +    int keys_count = 0;
 12.1303 +    sq_tpk_t *keys = NULL;
 12.1304 +    sq_tpk_t signer = NULL;
 12.1305 +    sq_writer_stack_t ws = NULL;
 12.1306 +
 12.1307 +    assert(session);
 12.1308 +    assert(keylist);
 12.1309 +    assert(ptext);
 12.1310 +    assert(psize);
 12.1311 +    assert(ctext);
 12.1312 +    assert(csize);
 12.1313 +
 12.1314 +    *ctext = NULL;
 12.1315 +    *csize = 0;
 12.1316 +
 12.1317 +    keys = calloc(stringlist_length(keylist), sizeof(*keys));
 12.1318 +    if (keys == NULL)
 12.1319 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
 12.1320 +
 12.1321 +    // Get the keys for the recipients.
 12.1322 +    const stringlist_t *_keylist;
 12.1323 +    for (_keylist = keylist; _keylist != NULL; _keylist = _keylist->next) {
 12.1324 +        assert(_keylist->value);
 12.1325 +        sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(_keylist->value);
 12.1326 +        status = tpk_find_by_fpr(session, sq_fpr, false, &keys[keys_count ++], NULL);
 12.1327 +        sq_fingerprint_free(sq_fpr);
 12.1328 +        ERROR_OUT(session, status, "Looking up key for recipient '%s'", _keylist->value);
 12.1329 +    }
 12.1330 +
 12.1331 +    if (sign) {
 12.1332 +        // The first key in the keylist is the signer.
 12.1333 +        status = tpk_find_by_fpr_hex(session, keylist->value, true, &signer, NULL);
 12.1334 +        ERROR_OUT(session, status, "Looking up key for signing '%s'", keylist->value);
 12.1335 +    }
 12.1336 +
 12.1337 +    sq_writer_t writer = sq_writer_alloc((void **) ctext, csize);
 12.1338 +    writer = sq_armor_writer_new(session->ctx, writer,
 12.1339 +                                 SQ_ARMOR_KIND_MESSAGE, NULL, 0);
 12.1340 +    if (!writer)
 12.1341 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Setting up armor writer");
 12.1342 +
 12.1343 +    ws = sq_writer_stack_message(writer);
 12.1344 +    ws = sq_encryptor_new (session->ctx, ws,
 12.1345 +                           NULL, 0, keys, keys_count,
 12.1346 +                           SQ_ENCRYPTION_MODE_FOR_TRANSPORT);
 12.1347 +    if (!ws) {
 12.1348 +        sq_writer_free(writer);
 12.1349 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Setting up encryptor");
 12.1350 +    }
 12.1351 +
 12.1352 +    if (sign) {
 12.1353 +        ws = sq_signer_new(session->ctx, ws, &signer, 1);
 12.1354 +        if (!ws)
 12.1355 +            ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Setting up signer");
 12.1356 +    }
 12.1357 +
 12.1358 +    ws = sq_literal_writer_new (session->ctx, ws);
 12.1359 +    if (!ws)
 12.1360 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Setting up literal writer");
 12.1361 +
 12.1362 +    sq_status_t write_status =
 12.1363 +        sq_writer_stack_write_all (session->ctx, ws,
 12.1364 +                                   (uint8_t *) ptext, psize);
 12.1365 +    if (write_status != 0)
 12.1366 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Encrypting message");
 12.1367 +
 12.1368 +    // Add a terminating NUL for naive users
 12.1369 +    void *t = realloc(*ctext, *csize + 1);
 12.1370 +    if (! t)
 12.1371 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "out of memory");
 12.1372 +    *ctext = t;
 12.1373 +    (*ctext)[*csize] = 0;
 12.1374 +
 12.1375 + out:
 12.1376 +    if (ws) {
 12.1377 +        sq_status_t sq_status = sq_writer_stack_finalize (session->ctx, ws);
 12.1378 +        ws = NULL;
 12.1379 +        if (sq_status != 0)
 12.1380 +            ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Flushing writer");
 12.1381 +    }
 12.1382 +
 12.1383 +    if (signer)
 12.1384 +        sq_tpk_free(signer);
 12.1385 +    for (int i = 0; i < keys_count; i ++)
 12.1386 +        sq_tpk_free(keys[i]);
 12.1387 +    free(keys);
 12.1388 +
 12.1389 +    T("-> %s", pep_status_to_string(status));
 12.1390 +    return status;
 12.1391 +}
 12.1392 +
 12.1393 +PEP_STATUS pgp_encrypt_only(
 12.1394 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
 12.1395 +    size_t psize, char **ctext, size_t *csize)
 12.1396 +{
 12.1397 +    return pgp_encrypt_sign_optional(session, keylist, ptext,
 12.1398 +        psize, ctext, csize, false);
 12.1399 +}
 12.1400 +
 12.1401 +PEP_STATUS pgp_encrypt_and_sign(
 12.1402 +    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
 12.1403 +    size_t psize, char **ctext, size_t *csize)
 12.1404 +{
 12.1405 +    return pgp_encrypt_sign_optional(session, keylist, ptext,
 12.1406 +        psize, ctext, csize, true);
 12.1407 +}
 12.1408 +
 12.1409 +
 12.1410 +PEP_STATUS pgp_generate_keypair(PEP_SESSION session, pEp_identity *identity)
 12.1411 +{
 12.1412 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1413 +    char *userid = NULL;
 12.1414 +    sq_tpk_t tpk = NULL;
 12.1415 +    sq_fingerprint_t sq_fpr = NULL;
 12.1416 +    char *fpr = NULL;
 12.1417 +
 12.1418 +    assert(session);
 12.1419 +    assert(identity);
 12.1420 +    assert(identity->address);
 12.1421 +    assert(identity->fpr == NULL || identity->fpr[0] == 0);
 12.1422 +    assert(identity->username);
 12.1423 +
 12.1424 +    asprintf(&userid, "%s <%s>", identity->username, identity->address);
 12.1425 +    if (! userid)
 12.1426 +        ERROR_OUT(session, PEP_OUT_OF_MEMORY, "asprintf");
 12.1427 +
 12.1428 +    T("(%s)", userid);
 12.1429 +
 12.1430 +    // Generate a key.
 12.1431 +    sq_tsk_t tsk;
 12.1432 +    sq_signature_t rev;
 12.1433 +    if (sq_tsk_new(session->ctx, userid, &tsk, &rev) != 0)
 12.1434 +        ERROR_OUT(session, PEP_CANNOT_CREATE_KEY, "Generating a key pair");
 12.1435 +
 12.1436 +    // XXX: We should return this.
 12.1437 +    // sq_signature_free(rev);
 12.1438 +
 12.1439 +    tpk = sq_tsk_into_tpk(tsk);
 12.1440 +
 12.1441 +    // Get the fingerprint.
 12.1442 +    sq_fpr = sq_tpk_fingerprint(tpk);
 12.1443 +    fpr = sq_fingerprint_to_hex(sq_fpr);
 12.1444 +
 12.1445 +    status = tpk_save(session, tpk, NULL);
 12.1446 +    tpk = NULL;
 12.1447 +    if (status != 0)
 12.1448 +        ERROR_OUT(session, PEP_CANNOT_CREATE_KEY, "saving TSK");
 12.1449 +
 12.1450 +    free(identity->fpr);
 12.1451 +    identity->fpr = fpr;
 12.1452 +    fpr = NULL;
 12.1453 +
 12.1454 + out:
 12.1455 +    if (sq_fpr)
 12.1456 +        sq_fingerprint_free(sq_fpr);
 12.1457 +    free(fpr);
 12.1458 +    if (tpk)
 12.1459 +        sq_tpk_free(tpk);
 12.1460 +    free(userid);
 12.1461 +
 12.1462 +    T("-> %s", pep_status_to_string(status));
 12.1463 +    return status;
 12.1464 +}
 12.1465 +
 12.1466 +PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr_raw)
 12.1467 +{
 12.1468 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1469 +    char *fpr = sq_fingerprint_canonicalize(fpr_raw);
 12.1470 +
 12.1471 +    T("(%s)", fpr);
 12.1472 +
 12.1473 +    // XXX: Can also be used for deleting public keys!!!
 12.1474 +    assert(!"implement me");
 12.1475 +
 12.1476 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.1477 +
 12.1478 +    free(fpr);
 12.1479 +    return status;
 12.1480 +}
 12.1481 +
 12.1482 +// XXX: This needs to handle not only TPKs, but also keyrings and
 12.1483 +// revocation certificates.  Right now, we only import a single TPK
 12.1484 +// and ignore everything else.
 12.1485 +PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
 12.1486 +                              size_t size, identity_list **private_idents)
 12.1487 +{
 12.1488 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1489 +
 12.1490 +    if (private_idents)
 12.1491 +        *private_idents = NULL;
 12.1492 +
 12.1493 +    T("parsing %zd bytes", size);
 12.1494 +
 12.1495 +    sq_packet_parser_result_t ppr
 12.1496 +        = sq_packet_parser_from_bytes(session->ctx, (uint8_t *) key_data, size);
 12.1497 +    if (! ppr)
 12.1498 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "Creating packet parser");
 12.1499 +
 12.1500 +    sq_tag_t tag = sq_packet_parser_result_tag(ppr);
 12.1501 +    switch (tag) {
 12.1502 +    case SQ_TAG_SIGNATURE:
 12.1503 +        // XXX: Implement me.
 12.1504 +        assert(!"Have possible revocation certificate!");
 12.1505 +        break;
 12.1506 +
 12.1507 +    case SQ_TAG_PUBLIC_KEY:
 12.1508 +    case SQ_TAG_SECRET_KEY: {
 12.1509 +        sq_tpk_t tpk = sq_tpk_from_packet_parser(session->ctx, ppr);
 12.1510 +        if (! tpk)
 12.1511 +            ERROR_OUT(session, PEP_UNKNOWN_ERROR, "parsing key data");
 12.1512 +
 12.1513 +        // If private_idents is not NULL and there is any private key
 12.1514 +        // material, it will be saved.
 12.1515 +        status = tpk_save(session, tpk, private_idents);
 12.1516 +        ERROR_OUT(session, status, "saving TPK");
 12.1517 +
 12.1518 +        break;
 12.1519 +    }
 12.1520 +    default:
 12.1521 +        ERROR_OUT(session, PEP_STATUS_OK,
 12.1522 +                  "Can't import %s", sq_tag_to_string(tag));
 12.1523 +        break;
 12.1524 +    }
 12.1525 +
 12.1526 + out:
 12.1527 +    T("-> %s", pep_status_to_string(status));
 12.1528 +    return status;
 12.1529 +}
 12.1530 +
 12.1531 +PEP_STATUS pgp_export_keydata(
 12.1532 +        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
 12.1533 +        bool secret)
 12.1534 +{
 12.1535 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1536 +    sq_tpk_t secret_key = NULL;
 12.1537 +    sq_tpk_t tpk = NULL;
 12.1538 +
 12.1539 +    assert(session);
 12.1540 +    assert(fpr);
 12.1541 +    assert(key_data);
 12.1542 +    assert(*key_data == NULL);
 12.1543 +    assert(size);
 12.1544 +
 12.1545 +    *size = 0;
 12.1546 +
 12.1547 +    T("(%s, %s)", fpr, secret ? "secret" : "public");
 12.1548 +
 12.1549 +    if (secret) {
 12.1550 +        status = tpk_find_by_fpr_hex(session, fpr, true, &secret_key, NULL);
 12.1551 +        if (status == PEP_KEY_NOT_FOUND)
 12.1552 +            status = PEP_STATUS_OK;
 12.1553 +        ERROR_OUT(session, status, "Looking up TSK for %s", fpr);
 12.1554 +    }
 12.1555 +
 12.1556 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
 12.1557 +    status = tpk_find_by_fpr(session, sq_fpr, false, &tpk, NULL);
 12.1558 +    sq_fingerprint_free(sq_fpr);
 12.1559 +    ERROR_OUT(session, status, "Looking up TPK for %s", fpr);
 12.1560 +
 12.1561 +    if (secret_key) {
 12.1562 +        tpk = sq_tpk_merge(session->ctx, tpk, secret_key);
 12.1563 +        // sq_tpk_merge can return NULL if the primary keys don't
 12.1564 +        // match.  But, we looked up the tpk by the secret key's
 12.1565 +        // fingerprint so this should not be possible.
 12.1566 +        assert(tpk);
 12.1567 +        secret_key = NULL;
 12.1568 +    }
 12.1569 +
 12.1570 +    sq_writer_t memory_writer = sq_writer_alloc((void **) key_data, size);
 12.1571 +    if (! memory_writer)
 12.1572 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "creating memory writer");
 12.1573 +    sq_writer_t armor_writer = sq_armor_writer_new(session->ctx,
 12.1574 +                                                   memory_writer,
 12.1575 +                                                   SQ_ARMOR_KIND_PUBLICKEY,
 12.1576 +                                                   NULL, 0);
 12.1577 +    if (! armor_writer) {
 12.1578 +        sq_writer_free(memory_writer);
 12.1579 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "creating armored writer");
 12.1580 +    }
 12.1581 +
 12.1582 +    if (secret) {
 12.1583 +        sq_tsk_t tsk = sq_tpk_into_tsk(tpk);
 12.1584 +        sq_tsk_serialize(session->ctx, tsk, armor_writer);
 12.1585 +        tpk = sq_tsk_into_tpk(tsk);
 12.1586 +    } else {
 12.1587 +        sq_tpk_serialize(session->ctx, tpk, armor_writer);
 12.1588 +    }
 12.1589 +
 12.1590 + out:
 12.1591 +    if (tpk)
 12.1592 +        sq_tpk_free(tpk);
 12.1593 +
 12.1594 +    if (armor_writer)
 12.1595 +        sq_writer_free(armor_writer);
 12.1596 +
 12.1597 +    if (secret_key)
 12.1598 +        sq_tpk_free(secret_key);
 12.1599 +
 12.1600 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.1601 +    return status;
 12.1602 +}
 12.1603 +
 12.1604 +char* _undot_address(const char* address) {
 12.1605 +    if (!address)
 12.1606 +        return NULL;
 12.1607 +
 12.1608 +    int addr_len = strlen(address);
 12.1609 +    const char* at = strstr(address, "@");
 12.1610 +
 12.1611 +    if (!at)
 12.1612 +        at = address + addr_len;
 12.1613 +
 12.1614 +    char* retval = calloc(1, addr_len + 1);
 12.1615 +
 12.1616 +    const char* addr_curr = address;
 12.1617 +    char* retval_curr = retval;
 12.1618 +
 12.1619 +    while (addr_curr < at) {
 12.1620 +        if (*addr_curr == '.') {
 12.1621 +            addr_curr++;
 12.1622 +            continue;
 12.1623 +        }
 12.1624 +        *retval_curr = *addr_curr;
 12.1625 +        retval_curr++;
 12.1626 +        addr_curr++;
 12.1627 +    }
 12.1628 +    if (*addr_curr == '@')
 12.1629 +        strcat(retval_curr, addr_curr);
 12.1630 +
 12.1631 +    return retval;
 12.1632 +}
 12.1633 +
 12.1634 +static stringpair_list_t *add_key(PEP_SESSION session,
 12.1635 +                                  stringpair_list_t *keyinfo_list,
 12.1636 +                                  stringlist_t* keylist,
 12.1637 +                                  sq_tpk_t tpk, sq_fingerprint_t fpr) {
 12.1638 +    bool revoked = false;
 12.1639 +    // Don't add revoked keys to the keyinfo_list.
 12.1640 +    if (keyinfo_list) {
 12.1641 +        sq_revocation_status_t rs = sq_tpk_revocation_status(tpk);
 12.1642 +        sq_revocation_status_variant_t rsv = sq_revocation_status_variant(rs);
 12.1643 +        sq_revocation_status_free(rs);
 12.1644 +        if (rsv == SQ_REVOCATION_STATUS_REVOKED)
 12.1645 +            revoked = true;
 12.1646 +    }
 12.1647 +
 12.1648 +    if (revoked && ! keylist)
 12.1649 +        return keyinfo_list;
 12.1650 +
 12.1651 +    int dealloc_fpr = 0;
 12.1652 +    if (!fpr) {
 12.1653 +        dealloc_fpr = 1;
 12.1654 +        fpr = sq_tpk_fingerprint(tpk);
 12.1655 +    }
 12.1656 +    char *fpr_str = sq_fingerprint_to_hex(fpr);
 12.1657 +
 12.1658 +    if (!revoked && keyinfo_list) {
 12.1659 +        char *user_id = sq_tpk_primary_user_id(tpk);
 12.1660 +        if (user_id)
 12.1661 +            keyinfo_list = stringpair_list_add(keyinfo_list,
 12.1662 +                                               new_stringpair(fpr_str, user_id));
 12.1663 +        free(user_id);
 12.1664 +    }
 12.1665 +
 12.1666 +    if (keylist)
 12.1667 +        keylist = stringlist_add(keylist, fpr_str);
 12.1668 +
 12.1669 +    free(fpr_str);
 12.1670 +    if (dealloc_fpr)
 12.1671 +        sq_fingerprint_free(fpr);
 12.1672 +
 12.1673 +    return keyinfo_list;
 12.1674 +}
 12.1675 +
 12.1676 +static PEP_STATUS list_keys(PEP_SESSION session,
 12.1677 +                            const char* pattern, int private_only,
 12.1678 +                            stringpair_list_t** keyinfo_list, stringlist_t** keylist)
 12.1679 +{
 12.1680 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1681 +    sq_tpk_t tpk = NULL;
 12.1682 +    sq_fingerprint_t fpr = NULL;
 12.1683 +
 12.1684 +    T("('%s', private: %d)", pattern, private_only);
 12.1685 +
 12.1686 +    stringpair_list_t* _keyinfo_list = NULL;
 12.1687 +    if (keyinfo_list) {
 12.1688 +        _keyinfo_list = new_stringpair_list(NULL);
 12.1689 +        if (!_keyinfo_list)
 12.1690 +            ERROR_OUT(session, PEP_OUT_OF_MEMORY, "new_stringpair_list");
 12.1691 +    }
 12.1692 +    stringlist_t* _keylist = NULL;
 12.1693 +    if (keylist) {
 12.1694 +        _keylist = new_stringlist(NULL);
 12.1695 +        if (!_keylist)
 12.1696 +            ERROR_OUT(session, PEP_OUT_OF_MEMORY, "new_string_list");
 12.1697 +    }
 12.1698 +
 12.1699 +    // Trim any leading space.  This also makes it easier to recognize
 12.1700 +    // a string that is only whitespace.
 12.1701 +    while (*pattern == ' ')
 12.1702 +        pattern ++;
 12.1703 +
 12.1704 +    if (strchr(pattern, '@')) {
 12.1705 +        // Looks like a mailbox.
 12.1706 +        sq_tpk_t *tpks = NULL;
 12.1707 +        int count = 0;
 12.1708 +        status = tpk_find_by_email(session, pattern, private_only, &tpks, &count);
 12.1709 +        ERROR_OUT(session, status, "Looking up '%s'", pattern);
 12.1710 +        for (int i = 0; i < count; i ++) {
 12.1711 +            add_key(session, _keyinfo_list, _keylist, tpks[i], NULL);
 12.1712 +            sq_tpk_free(tpks[i]);
 12.1713 +        }
 12.1714 +        free(tpks);
 12.1715 +
 12.1716 +        if (count == 0) {
 12.1717 +            // If match failed, check to see if we've got a dotted
 12.1718 +            // address in the pattern.  If so, try again without dots.
 12.1719 +            const char* dotpos = strstr(pattern, ".");
 12.1720 +            const char* atpos = strstr(pattern, "@");
 12.1721 +            if (dotpos && atpos && (dotpos < atpos)) {
 12.1722 +                char* undotted = _undot_address(pattern);
 12.1723 +                if (undotted) {
 12.1724 +                    PEP_STATUS status = list_keys(session, undotted, private_only,
 12.1725 +                                                  keyinfo_list, keylist);
 12.1726 +                    free(undotted);
 12.1727 +                    return status;
 12.1728 +                }
 12.1729 +            }
 12.1730 +        }
 12.1731 +    } else if (// Only hex characters and spaces
 12.1732 +               pattern[strspn(pattern, "0123456789aAbBcCdDeEfF ")] == 0
 12.1733 +               // And a fair amount of them.
 12.1734 +               && strlen(pattern) >= 16) {
 12.1735 +        // Fingerprint.
 12.1736 +        fpr = sq_fingerprint_from_hex(pattern);
 12.1737 +        status = tpk_find_by_fpr(session, fpr, false, &tpk, NULL);
 12.1738 +        ERROR_OUT(session, status, "Looking up key");
 12.1739 +        add_key(session, _keyinfo_list, _keylist, tpk, fpr);
 12.1740 +    } else if (pattern[0] == 0) {
 12.1741 +        // Empty string.
 12.1742 +
 12.1743 +        sq_tpk_t *tpks = NULL;
 12.1744 +        int count = 0;
 12.1745 +        status = tpk_all(session, private_only, &tpks, &count);
 12.1746 +        ERROR_OUT(session, status, "Looking up '%s'", pattern);
 12.1747 +        for (int i = 0; i < count; i ++) {
 12.1748 +            add_key(session, _keyinfo_list, _keylist, tpks[i], NULL);
 12.1749 +            sq_tpk_free(tpks[i]);
 12.1750 +        }
 12.1751 +        free(tpks);
 12.1752 +    } else {
 12.1753 +        T("unsupported pattern '%s'", pattern);
 12.1754 +    }
 12.1755 +
 12.1756 + out:
 12.1757 +    if (tpk)
 12.1758 +        sq_tpk_free(tpk);
 12.1759 +    if (fpr)
 12.1760 +        sq_fingerprint_free(fpr);
 12.1761 +
 12.1762 +    if (status == PEP_KEY_NOT_FOUND)
 12.1763 +        status = PEP_STATUS_OK;
 12.1764 +
 12.1765 +    if (status != PEP_STATUS_OK || (_keyinfo_list && !_keyinfo_list->value)) {
 12.1766 +        free_stringpair_list(_keyinfo_list);
 12.1767 +        _keyinfo_list = NULL;
 12.1768 +    }
 12.1769 +    if (keyinfo_list)
 12.1770 +        *keyinfo_list = _keyinfo_list;
 12.1771 +
 12.1772 +    if (status != PEP_STATUS_OK || (_keylist && !_keylist->value)) {
 12.1773 +        free_stringlist(_keylist);
 12.1774 +        _keylist = NULL;
 12.1775 +    }
 12.1776 +    if (keylist)
 12.1777 +        *keylist = _keylist;
 12.1778 +
 12.1779 +    int len = -1;
 12.1780 +    if (keylist)
 12.1781 +        len = stringlist_length(*keylist);
 12.1782 +    else if (keyinfo_list)
 12.1783 +        len = stringpair_list_length(*keyinfo_list);
 12.1784 +    T("(%s) -> %s (%d keys)", pattern, pep_status_to_string(status), len);
 12.1785 +    return status;
 12.1786 +}
 12.1787 +
 12.1788 +// pattern could be empty, an fpr, or a mailbox.
 12.1789 +//
 12.1790 +// keyinfo_list is a list of <fpr, openpgp userid> tuples for the
 12.1791 +// matching keys.
 12.1792 +//
 12.1793 +// This function filters out revoked key, but not expired keys.
 12.1794 +PEP_STATUS pgp_list_keyinfo(PEP_SESSION session,
 12.1795 +                            const char* pattern,
 12.1796 +                            stringpair_list_t** keyinfo_list)
 12.1797 +{
 12.1798 +    return list_keys(session, pattern, false, keyinfo_list, NULL);
 12.1799 +}
 12.1800 +
 12.1801 +PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
 12.1802 +{
 12.1803 +    assert(!"pgp_recv_key not implemented");
 12.1804 +    return PEP_UNKNOWN_ERROR;
 12.1805 +}
 12.1806 +
 12.1807 +// Unlike pgp_list_keyinfo, this function returns revoked keys.
 12.1808 +PEP_STATUS pgp_find_keys(
 12.1809 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist)
 12.1810 +{
 12.1811 +    return list_keys(session, pattern, false, NULL, keylist);
 12.1812 +}
 12.1813 +
 12.1814 +// Unlike pgp_list_keyinfo, this function returns revoked keys.
 12.1815 +PEP_STATUS pgp_find_private_keys(
 12.1816 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist)
 12.1817 +{
 12.1818 +    return list_keys(session, pattern, true, NULL, keylist);
 12.1819 +}
 12.1820 +
 12.1821 +PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
 12.1822 +{
 12.1823 +    assert(!"pgp_send_key not implemented");
 12.1824 +    return PEP_UNKNOWN_ERROR;
 12.1825 +}
 12.1826 +
 12.1827 +PEP_STATUS pgp_get_key_rating(
 12.1828 +    PEP_SESSION session, const char *fpr, PEP_comm_type *comm_type)
 12.1829 +{
 12.1830 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1831 +    sq_tpk_t tpk = NULL;
 12.1832 +
 12.1833 +    assert(session);
 12.1834 +    assert(fpr);
 12.1835 +    assert(comm_type);
 12.1836 +
 12.1837 +    *comm_type = PEP_ct_unknown;
 12.1838 +
 12.1839 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
 12.1840 +    status = tpk_find_by_fpr(session, sq_fpr, false, &tpk, NULL);
 12.1841 +    sq_fingerprint_free(sq_fpr);
 12.1842 +    ERROR_OUT(session, status, "Looking up key: %s", fpr);
 12.1843 +
 12.1844 +    *comm_type = PEP_ct_OpenPGP_unconfirmed;
 12.1845 +
 12.1846 +    if (sq_tpk_expired(tpk)) {
 12.1847 +        *comm_type = PEP_ct_key_expired;
 12.1848 +        goto out;
 12.1849 +    }
 12.1850 +
 12.1851 +    sq_revocation_status_t rs = sq_tpk_revocation_status(tpk);
 12.1852 +    sq_revocation_status_variant_t rsv = sq_revocation_status_variant(rs);
 12.1853 +    sq_revocation_status_free(rs);
 12.1854 +    if (rsv == SQ_REVOCATION_STATUS_REVOKED) {
 12.1855 +        *comm_type = PEP_ct_key_revoked;
 12.1856 +        goto out;
 12.1857 +    }
 12.1858 +
 12.1859 +    PEP_comm_type best_enc = PEP_ct_no_encryption, best_sign = PEP_ct_no_encryption;
 12.1860 +    sq_tpk_key_iter_t key_iter = sq_tpk_key_iter(tpk);
 12.1861 +    sq_p_key_t key;
 12.1862 +    sq_signature_t sig;
 12.1863 +    sq_revocation_status_t rev;
 12.1864 +    while ((key = sq_tpk_key_iter_next(key_iter, &sig, &rev))) {
 12.1865 +        if (! sig)
 12.1866 +            continue;
 12.1867 +
 12.1868 +        if (sq_revocation_status_variant(rev) == SQ_REVOCATION_STATUS_REVOKED)
 12.1869 +            continue;
 12.1870 +
 12.1871 +        if (! sq_p_key_alive(key, sig))
 12.1872 +            continue;
 12.1873 +
 12.1874 +        PEP_comm_type curr = PEP_ct_no_encryption;
 12.1875 +
 12.1876 +        int can_enc = sq_signature_can_encrypt_for_transport(sig)
 12.1877 +            || sq_signature_can_encrypt_at_rest(sig);
 12.1878 +        int can_sign = sq_signature_can_sign(sig);
 12.1879 +
 12.1880 +        sq_public_key_algo_t pk_algo = sq_p_key_public_key_algo(key);
 12.1881 +        if (pk_algo == SQ_PUBLIC_KEY_ALGO_RSA_ENCRYPT_SIGN
 12.1882 +            || pk_algo == SQ_PUBLIC_KEY_ALGO_RSA_ENCRYPT
 12.1883 +            || pk_algo == SQ_PUBLIC_KEY_ALGO_RSA_SIGN) {
 12.1884 +            int bits = sq_p_key_public_key_bits(key);
 12.1885 +            if (bits < 1024)
 12.1886 +                curr = PEP_ct_key_too_short;
 12.1887 +            else if (bits == 1024)
 12.1888 +                curr = PEP_ct_OpenPGP_weak_unconfirmed;
 12.1889 +            else
 12.1890 +                curr = PEP_ct_OpenPGP_unconfirmed;
 12.1891 +        } else {
 12.1892 +            curr = PEP_ct_OpenPGP_unconfirmed;
 12.1893 +        }
 12.1894 +
 12.1895 +        if (can_enc)
 12.1896 +            best_enc = _MAX(best_enc, curr);
 12.1897 +
 12.1898 +        if (can_sign)
 12.1899 +            best_sign = _MAX(best_sign, curr);
 12.1900 +    }
 12.1901 +    sq_tpk_key_iter_free(key_iter);
 12.1902 +
 12.1903 +    if (best_enc == PEP_ct_no_encryption || best_sign == PEP_ct_no_encryption) {
 12.1904 +        *comm_type = PEP_ct_key_b0rken;
 12.1905 +        goto out;
 12.1906 +    } else {
 12.1907 +        *comm_type = _MIN(best_enc, best_sign);
 12.1908 +    }
 12.1909 +
 12.1910 + out:
 12.1911 +    if (tpk)
 12.1912 +        sq_tpk_free(tpk);
 12.1913 +
 12.1914 +    T("(%s) -> %s", fpr, pep_comm_type_to_string(*comm_type));
 12.1915 +    return status;
 12.1916 +}
 12.1917 +
 12.1918 +
 12.1919 +PEP_STATUS pgp_renew_key(
 12.1920 +    PEP_SESSION session, const char *fpr, const timestamp *ts)
 12.1921 +{
 12.1922 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1923 +    sq_tpk_t tpk = NULL;
 12.1924 +    time_t t = mktime((struct tm *) ts);
 12.1925 +
 12.1926 +    T("(%s)", fpr);
 12.1927 +
 12.1928 +    status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
 12.1929 +    ERROR_OUT(session, status, "Looking up '%s'", fpr);
 12.1930 +
 12.1931 +    uint32_t creation_time = sq_p_key_creation_time(sq_tpk_primary(tpk));
 12.1932 +    if (creation_time > t)
 12.1933 +        // The creation time is after the expiration time!
 12.1934 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR,
 12.1935 +                  "creation time can't be after expiration time");
 12.1936 +
 12.1937 +    uint32_t delta = t - creation_time;
 12.1938 +    tpk = sq_tpk_set_expiry(session->ctx, tpk, delta);
 12.1939 +    if (! tpk)
 12.1940 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "setting expiration");
 12.1941 +
 12.1942 +    status = tpk_save(session, tpk, NULL);
 12.1943 +    tpk = NULL;
 12.1944 +    ERROR_OUT(session, status, "Saving %s", fpr);
 12.1945 +
 12.1946 + out:
 12.1947 +    if (tpk)
 12.1948 +        sq_tpk_free(tpk);
 12.1949 +
 12.1950 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.1951 +    return status;
 12.1952 +}
 12.1953 +
 12.1954 +PEP_STATUS pgp_revoke_key(
 12.1955 +    PEP_SESSION session, const char *fpr, const char *reason)
 12.1956 +{
 12.1957 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1958 +    sq_tpk_t tpk = NULL;
 12.1959 +
 12.1960 +    T("(%s)", fpr);
 12.1961 +
 12.1962 +    status = tpk_find_by_fpr_hex(session, fpr, true, &tpk, NULL);
 12.1963 +    ERROR_OUT(session, status, "Looking up %s", fpr);
 12.1964 +
 12.1965 +    tpk = sq_tpk_revoke_in_place(session->ctx, tpk,
 12.1966 +                                 SQ_REASON_FOR_REVOCATION_UNSPECIFIED,
 12.1967 +                                 reason);
 12.1968 +    if (! tpk)
 12.1969 +        ERROR_OUT(session, PEP_UNKNOWN_ERROR, "setting expiration");
 12.1970 +
 12.1971 +    assert(sq_revocation_status_variant(sq_tpk_revocation_status(tpk))
 12.1972 +           == SQ_REVOCATION_STATUS_REVOKED);
 12.1973 +
 12.1974 +    status = tpk_save(session, tpk, NULL);
 12.1975 +    tpk = NULL;
 12.1976 +    ERROR_OUT(session, status, "Saving %s", fpr);
 12.1977 +
 12.1978 + out:
 12.1979 +    if (tpk)
 12.1980 +        sq_tpk_free(tpk);
 12.1981 +
 12.1982 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.1983 +    return status;
 12.1984 +}
 12.1985 +
 12.1986 +PEP_STATUS pgp_key_expired(PEP_SESSION session, const char *fpr,
 12.1987 +                           const time_t when, bool *expired)
 12.1988 +{
 12.1989 +    PEP_STATUS status = PEP_STATUS_OK;
 12.1990 +    sq_tpk_t tpk = NULL;
 12.1991 +    T("(%s)", fpr);
 12.1992 +
 12.1993 +    assert(session);
 12.1994 +    assert(fpr);
 12.1995 +    assert(expired);
 12.1996 +
 12.1997 +    *expired = false;
 12.1998 +
 12.1999 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
 12.2000 +    status = tpk_find_by_fpr(session, sq_fpr, false, &tpk, NULL);
 12.2001 +    sq_fingerprint_free(sq_fpr);
 12.2002 +    ERROR_OUT(session, status, "Looking up %s", fpr);
 12.2003 +
 12.2004 +    // Is the TPK live?
 12.2005 +    *expired = !sq_tpk_alive_at(tpk, when);
 12.2006 +    if (*expired)
 12.2007 +        goto out;
 12.2008 +
 12.2009 +    // Are there at least one certification subkey, one signing subkey
 12.2010 +    // and one encryption subkey that are live?
 12.2011 +    int can_certify = 0, can_encrypt = 0, can_sign = 0;
 12.2012 +
 12.2013 +    sq_tpk_key_iter_t key_iter = sq_tpk_key_iter(tpk);
 12.2014 +    sq_p_key_t key;
 12.2015 +    sq_signature_t sig;
 12.2016 +    sq_revocation_status_t rev;
 12.2017 +    while ((key = sq_tpk_key_iter_next(key_iter, &sig, &rev))) {
 12.2018 +        if (! sig)
 12.2019 +            continue;
 12.2020 +
 12.2021 +        if (sq_revocation_status_variant(rev) == SQ_REVOCATION_STATUS_REVOKED)
 12.2022 +            continue;
 12.2023 +
 12.2024 +        if (!sq_p_key_alive_at(key, sig, when))
 12.2025 +            continue;
 12.2026 +
 12.2027 +        if (sq_signature_can_encrypt_for_transport(sig)
 12.2028 +            || sq_signature_can_encrypt_at_rest(sig))
 12.2029 +            can_encrypt = 1;
 12.2030 +        if (sq_signature_can_sign(sig))
 12.2031 +            can_sign = 1;
 12.2032 +        if (sq_signature_can_certify(sig))
 12.2033 +            can_certify = 1;
 12.2034 +
 12.2035 +        if (can_encrypt && can_sign && can_certify)
 12.2036 +            break;
 12.2037 +    }
 12.2038 +    sq_tpk_key_iter_free(key_iter);
 12.2039 +
 12.2040 +    *expired = !(can_encrypt && can_sign && can_certify);
 12.2041 +
 12.2042 + out:
 12.2043 +    if (tpk)
 12.2044 +        sq_tpk_free(tpk);
 12.2045 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.2046 +    return status;
 12.2047 +}
 12.2048 +
 12.2049 +PEP_STATUS pgp_key_revoked(PEP_SESSION session, const char *fpr, bool *revoked)
 12.2050 +{
 12.2051 +    PEP_STATUS status = PEP_STATUS_OK;
 12.2052 +    sq_tpk_t tpk;
 12.2053 +
 12.2054 +    T("(%s)", fpr);
 12.2055 +
 12.2056 +    assert(session);
 12.2057 +    assert(fpr);
 12.2058 +    assert(revoked);
 12.2059 +
 12.2060 +    *revoked = false;
 12.2061 +
 12.2062 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
 12.2063 +    status = tpk_find_by_fpr(session, sq_fpr, false, &tpk, NULL);
 12.2064 +    sq_fingerprint_free(sq_fpr);
 12.2065 +    ERROR_OUT(session, status, "Looking up %s", fpr);
 12.2066 +
 12.2067 +    sq_revocation_status_t rs = sq_tpk_revocation_status(tpk);
 12.2068 +    *revoked = sq_revocation_status_variant(rs) == SQ_REVOCATION_STATUS_REVOKED;
 12.2069 +    sq_revocation_status_free (rs);
 12.2070 +    sq_tpk_free(tpk);
 12.2071 +
 12.2072 + out:
 12.2073 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.2074 +    return status;
 12.2075 +}
 12.2076 +
 12.2077 +PEP_STATUS pgp_key_created(PEP_SESSION session, const char *fpr, time_t *created)
 12.2078 +{
 12.2079 +    PEP_STATUS status = PEP_STATUS_OK;
 12.2080 +    sq_tpk_t tpk = NULL;
 12.2081 +    T("(%s)", fpr);
 12.2082 +
 12.2083 +    *created = 0;
 12.2084 +
 12.2085 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
 12.2086 +    status = tpk_find_by_fpr(session, sq_fpr, false, &tpk, NULL);
 12.2087 +    sq_fingerprint_free(sq_fpr);
 12.2088 +    ERROR_OUT(session, status, "Looking up %s", fpr);
 12.2089 +
 12.2090 +    sq_p_key_t k = sq_tpk_primary(tpk);
 12.2091 +    *created = sq_p_key_creation_time(k);
 12.2092 +    sq_tpk_free(tpk);
 12.2093 +
 12.2094 + out:
 12.2095 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.2096 +    return status;
 12.2097 +}
 12.2098 +
 12.2099 +PEP_STATUS pgp_binary(const char **path)
 12.2100 +{
 12.2101 +    return PEP_STATUS_OK;
 12.2102 +}
 12.2103 +
 12.2104 +PEP_STATUS pgp_contains_priv_key(PEP_SESSION session, const char *fpr,
 12.2105 +                                 bool *has_private)
 12.2106 +{
 12.2107 +    T("(%s)", fpr);
 12.2108 +    sq_fingerprint_t sq_fpr = sq_fingerprint_from_hex(fpr);
 12.2109 +    PEP_STATUS status = tpk_find_by_fpr(session, sq_fpr, true, NULL, NULL);
 12.2110 +    sq_fingerprint_free(sq_fpr);
 12.2111 +    if (status == PEP_STATUS_OK) {
 12.2112 +        *has_private = 1;
 12.2113 +    } else if (status == PEP_KEY_NOT_FOUND) {
 12.2114 +        *has_private = 0;
 12.2115 +        status = PEP_STATUS_OK;
 12.2116 +    }
 12.2117 +    T("(%s) -> %s", fpr, pep_status_to_string(status));
 12.2118 +    return status;
 12.2119 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/pgp_sequoia.h	Wed Jan 23 11:59:43 2019 +0100
    13.3 @@ -0,0 +1,115 @@
    13.4 +// This file is under GNU General Public License 3.0
    13.5 +// see LICENSE.txt
    13.6 +
    13.7 +#pragma once
    13.8 +
    13.9 +#include "pEpEngine.h"
   13.10 +
   13.11 +PEP_STATUS pgp_init(PEP_SESSION session, bool in_first);
   13.12 +void pgp_release(PEP_SESSION session, bool out_last);
   13.13 +
   13.14 +PEP_STATUS pgp_decrypt_and_verify(
   13.15 +        PEP_SESSION session, const char *ctext, size_t csize,
   13.16 +        const char *dsigtext, size_t dsigsize,
   13.17 +        char **ptext, size_t *psize, stringlist_t **keylist,
   13.18 +        char** filename_ptr
   13.19 +    );
   13.20 +
   13.21 +PEP_STATUS pgp_encrypt_and_sign(
   13.22 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   13.23 +        size_t psize, char **ctext, size_t *csize
   13.24 +    );
   13.25 +
   13.26 +PEP_STATUS pgp_sign_only(
   13.27 +        PEP_SESSION session, const char* fpr, const char *ptext,
   13.28 +        size_t psize, char **stext, size_t *ssize
   13.29 +    );
   13.30 +
   13.31 +PEP_STATUS pgp_encrypt_only(
   13.32 +        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
   13.33 +        size_t psize, char **ctext, size_t *csize
   13.34 +    );
   13.35 +
   13.36 +
   13.37 +PEP_STATUS pgp_verify_text(
   13.38 +        PEP_SESSION session, const char *text, size_t size,
   13.39 +        const char *signature, size_t sig_size, stringlist_t **keylist
   13.40 +    );
   13.41 +
   13.42 +PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr);
   13.43 +
   13.44 +PEP_STATUS pgp_export_keydata(
   13.45 +        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
   13.46 +        bool secret
   13.47 +    );
   13.48 +
   13.49 +PEP_STATUS pgp_find_keys(
   13.50 +        PEP_SESSION session, const char *pattern, stringlist_t **keylist
   13.51 +    );
   13.52 +
   13.53 +PEP_STATUS pgp_list_keyinfo(
   13.54 +        PEP_SESSION session, const char* pattern, stringpair_list_t** keyinfo_list
   13.55 +    );
   13.56 +
   13.57 +PEP_STATUS pgp_generate_keypair(
   13.58 +        PEP_SESSION session, pEp_identity *identity
   13.59 +    );
   13.60 +
   13.61 +PEP_STATUS pgp_get_key_rating(
   13.62 +        PEP_SESSION session,
   13.63 +        const char *fpr,
   13.64 +        PEP_comm_type *comm_type
   13.65 +    );
   13.66 +
   13.67 +PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
   13.68 +                              size_t size, identity_list **private_idents);
   13.69 +
   13.70 +PEP_STATUS pgp_import_private_keydata(PEP_SESSION session, const char *key_data,
   13.71 +                                      size_t size, identity_list **private_idents);
   13.72 +
   13.73 +PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern);
   13.74 +PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern);
   13.75 +
   13.76 +PEP_STATUS pgp_renew_key(
   13.77 +        PEP_SESSION session,
   13.78 +        const char *fpr,
   13.79 +        const timestamp *ts
   13.80 +    );
   13.81 +
   13.82 +PEP_STATUS pgp_revoke_key(
   13.83 +        PEP_SESSION session,
   13.84 +        const char *fpr,
   13.85 +        const char *reason
   13.86 +    );
   13.87 +
   13.88 +PEP_STATUS pgp_key_expired(
   13.89 +        PEP_SESSION session,
   13.90 +        const char *fpr,
   13.91 +        const time_t when,
   13.92 +        bool *expired
   13.93 +    );
   13.94 +
   13.95 +PEP_STATUS pgp_key_revoked(
   13.96 +        PEP_SESSION session,
   13.97 +        const char *fpr,
   13.98 +        bool *revoked
   13.99 +    );
  13.100 +
  13.101 +PEP_STATUS pgp_key_created(
  13.102 +        PEP_SESSION session,
  13.103 +        const char *fpr,
  13.104 +        time_t *created
  13.105 +    );
  13.106 +
  13.107 +PEP_STATUS pgp_contains_priv_key(
  13.108 +        PEP_SESSION session, 
  13.109 +        const char *fpr,
  13.110 +        bool *has_private);
  13.111 +
  13.112 +PEP_STATUS pgp_find_private_keys(
  13.113 +    PEP_SESSION session, const char *pattern, stringlist_t **keylist
  13.114 +);
  13.115 +
  13.116 +PEP_STATUS pgp_binary(const char **path);
  13.117 +
  13.118 +#define PGP_BINARY_PATH pgp_binary
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/pgp_sequoia_internal.h	Wed Jan 23 11:59:43 2019 +0100
    14.3 @@ -0,0 +1,6 @@
    14.4 +// This file is under GNU General Public License 3.0
    14.5 +// see LICENSE.txt
    14.6 +
    14.7 +#pragma once
    14.8 +
    14.9 +#include <sequoia.h>
    15.1 --- a/src/stringlist.c	Mon Dec 24 15:32:27 2018 +0100
    15.2 +++ b/src/stringlist.c	Wed Jan 23 11:59:43 2019 +0100
    15.3 @@ -145,7 +145,9 @@
    15.4              found = true;
    15.5          list_curr = list_curr->next;
    15.6      }
    15.7 -     
    15.8 +    if(strcmp(list_curr->value,value)==0)
    15.9 +        found = true;
   15.10 +
   15.11      if (!found) {
   15.12          list_curr->next = new_stringlist(value);
   15.13  
    16.1 --- a/test/Makefile	Mon Dec 24 15:32:27 2018 +0100
    16.2 +++ b/test/Makefile	Wed Jan 23 11:59:43 2019 +0100
    16.3 @@ -34,6 +34,13 @@
    16.4      LDLIBS+= -luuid
    16.5  endif
    16.6  
    16.7 +ifeq ($(OPENPGP),SEQUOIA)
    16.8 +	LDFLAGS+= $(SEQUOIA_LDFLAGS)
    16.9 +	LDLIBS+= $(SEQUOIA_LIB)
   16.10 +	CFLAGS+= $(SEQUOIA_CFLAGS) -DUSE_SEQUOIA
   16.11 +	INC_FLAGS+= $(SEQUOIA_INC)
   16.12 +endif
   16.13 +
   16.14  ifdef SQLITE3_FROM_OS
   16.15      LDLIBS+= -lsqlite3
   16.16  endif
   16.17 @@ -116,7 +123,7 @@
   16.18  
   16.19  .PHONY: test
   16.20  test: all
   16.21 -	$(TEST_CMD_PFX) $(TEST_DEBUGGER) ./$(TARGET)
   16.22 +    $(TEST_CMD_PFX) $(TEST_DEBUGGER) ./$(TARGET)
   16.23  
   16.24  .PHONY: clean
   16.25  clean:
    17.1 --- a/test/convenience_scripts/keygen_for_test.py	Mon Dec 24 15:32:27 2018 +0100
    17.2 +++ b/test/convenience_scripts/keygen_for_test.py	Wed Jan 23 11:59:43 2019 +0100
    17.3 @@ -85,7 +85,7 @@
    17.4  
    17.5      
    17.6      pubkey = gpg.export_keys(fpr)
    17.7 -    privkey = gpg.export_keys(fpr, True, passphrase="")
    17.8 +    privkey = gpg.export_keys(fpr, True)
    17.9  
   17.10      pubkey_filename = os.path.join(pub_path, key_filename_prefix + "pub.asc")
   17.11      privkey_filename = os.path.join(priv_path, key_filename_prefix + "priv.asc")    
   17.12 @@ -99,7 +99,7 @@
   17.13      privkey_file.close()
   17.14          
   17.15      # Delete keys from keyring
   17.16 -    gpg.delete_keys(fpr, True, passphrase="") # True => private keys
   17.17 +    gpg.delete_keys(fpr, True) # True => private keys
   17.18      gpg.delete_keys(fpr)
   17.19  
   17.20      if (args.hgadd):
    18.1 --- a/test/include/EngineTestSuite.h	Mon Dec 24 15:32:27 2018 +0100
    18.2 +++ b/test/include/EngineTestSuite.h	Wed Jan 23 11:59:43 2019 +0100
    18.3 @@ -59,6 +59,5 @@
    18.4          void add_file_to_gpg_dir_queue(std::string copy_from, std::string dst_fname);    
    18.5          void add_file_to_home_dir_queue(std::string copy_from, std::string dst_fname);
    18.6          void process_file_queue(std::string dirname, std::vector<std::pair<std::string, std::string>> file_queue);
    18.7 -
    18.8  };
    18.9  #endif
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/test/include/SubkeyRatingEvalTests.h	Wed Jan 23 11:59:43 2019 +0100
    19.3 @@ -0,0 +1,29 @@
    19.4 +// This file is under GNU General Public License 3.0
    19.5 +// see LICENSE.txt
    19.6 +
    19.7 +#ifndef SUBKEY_RATING_EVAL_H
    19.8 +#define SUBKEY_RATING_EVAL_H
    19.9 +
   19.10 +#include <string>
   19.11 +#include "EngineTestIndividualSuite.h"
   19.12 +
   19.13 +using namespace std;
   19.14 +
   19.15 +class SubkeyRatingEvalTests : public EngineTestIndividualSuite {
   19.16 +    public:
   19.17 +        SubkeyRatingEvalTests(string test_suite, string test_home_dir);
   19.18 +    private:
   19.19 +        void check_subkey_rating_eval();
   19.20 +        void check_subkey_rating_eval_no_es();
   19.21 +        void check_subkey_rating_eval_weak_s();    
   19.22 +        void check_subkey_rating_eval_ecc_s();
   19.23 +        void check_subkey_rating_eval_weak_e_strong_ecc_se();
   19.24 +        void check_subkey_rating_eval_bad_es();
   19.25 +        void check_subkey_rating_eval_bad_e();
   19.26 +        void check_subkey_rating_eval_bad_s_ecc_e();    
   19.27 +        void check_subkey_rating_eval_revoked_sign_no_alt();    
   19.28 +        void check_subkey_rating_eval_revoked_e_with_alt();            
   19.29 +
   19.30 +};
   19.31 +
   19.32 +#endif
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/test/include/pEpTestStatic.h	Wed Jan 23 11:59:43 2019 +0100
    20.3 @@ -0,0 +1,25 @@
    20.4 +// This file is under GNU General Public License 3.0
    20.5 +// see LICENSE.txt
    20.6 +
    20.7 +#ifndef PEP_TEST_STATIC_H
    20.8 +#define PEP_TEST_STATIC_H
    20.9 +
   20.10 +#include <string>
   20.11 +
   20.12 +using namespace std;
   20.13 +
   20.14 +class pEpTestStatic {
   20.15 +    public:
   20.16 +        static size_t getMaxPathSize();
   20.17 +        static size_t sun_path_size;
   20.18 +        static size_t getAvailablePathChars(string keypath_str);
   20.19 +        static size_t available_path_chars;
   20.20 +        static const size_t classname_chars;
   20.21 +        static const size_t testnum_path_chars;
   20.22 +        static const size_t max_test_num;
   20.23 +
   20.24 +    private:
   20.25 +        pEpTestStatic() {};
   20.26 +};
   20.27 +
   20.28 +#endif
    21.1 --- a/test/src/EngineTestSuite.cc	Mon Dec 24 15:32:27 2018 +0100
    21.2 +++ b/test/src/EngineTestSuite.cc	Wed Jan 23 11:59:43 2019 +0100
    21.3 @@ -18,6 +18,8 @@
    21.4  
    21.5  #include "test_util.h"
    21.6  #include "EngineTestSuite.h"
    21.7 +#include "pEpTestStatic.h"
    21.8 +#include <algorithm>
    21.9  
   21.10  using namespace std;
   21.11  
   21.12 @@ -98,11 +100,11 @@
   21.13      
   21.14      set_my_name();
   21.15  
   21.16 +// FIXME
   21.17  #ifndef USE_NETPGP
   21.18      success = system("gpgconf --kill all");
   21.19      if (success != 0)
   21.20 -        throw std::runtime_error("SETUP: Error when executing 'gpgconf --kill all'.");
   21.21 - //   sleep(1); // hopefully enough time for the system to recognise that it is dead. *sigh*    
   21.22 +        throw std::runtime_error("SETUP: Error when executing 'gpgconf --kill all'.");    
   21.23  #endif
   21.24  
   21.25      if (stat(test_home.c_str(), &dirchk) == 0) {
   21.26 @@ -122,10 +124,20 @@
   21.27              throw std::runtime_error("Error creating a test directory.");
   21.28      }
   21.29  
   21.30 +    if (my_name.size() > pEpTestStatic::classname_chars)
   21.31 +        my_name.resize(pEpTestStatic::classname_chars);
   21.32 +
   21.33 +    if (on_test_number > pEpTestStatic::max_test_num) {
   21.34 +        cerr << "Warning - there are at least " << pEpTestStatic::max_test_num << " tests in this suite. While this probably won't cause "
   21.35 +             << endl << "problems, there is an obscure possibility that if your test path is REALLY REALLY LONG, tests will fail because gpg-agent "
   21.36 +             << endl << "won't start with huge paths. In general, however, we stop well before these limits, and pEpTestStatic::testnum_path_chars "
   21.37 +             << endl << "is overly conservative, so you probably don't need to worry." << endl;
   21.38 +    }    
   21.39 +
   21.40      temp_test_home = test_home + "/" + my_name;
   21.41      
   21.42      int errchk = mkdir(temp_test_home.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
   21.43 -    if (errchk != 0)
   21.44 +    if (errchk != 0 && errno != EEXIST)
   21.45          throw std::runtime_error("Error creating a test directory.");
   21.46  
   21.47      temp_test_home += "/" + to_string(on_test_number);
   21.48 @@ -134,7 +146,6 @@
   21.49      if (errchk != 0)
   21.50          throw std::runtime_error("Error creating a test directory.");
   21.51  
   21.52 -
   21.53      // TODO: This is *nix specific, which the current testing env is anyway,
   21.54      // but it needn't remain so forever and always
   21.55  
   21.56 @@ -205,6 +216,8 @@
   21.57      
   21.58  //    cout << "calling init()\n";
   21.59      PEP_STATUS status = init(&session, cached_messageToSend, cached_inject_sync_event);
   21.60 +    system("gpg-connect-agent /bye");   // Just in case - otherwise, we die on MacOS sometimes. Is this enough??
   21.61 +
   21.62      assert(status == PEP_STATUS_OK);
   21.63      assert(session);
   21.64  //    cout << "init() completed.\n";
    22.1 --- a/test/src/SuiteMaker.cc	Mon Dec 24 15:32:27 2018 +0100
    22.2 +++ b/test/src/SuiteMaker.cc	Wed Jan 23 11:59:43 2019 +0100
    22.3 @@ -12,191 +12,195 @@
    22.4  #include "SuiteMaker.h"
    22.5  
    22.6  // Begin where we generate stuff
    22.7 -#include "DecorateTests.h"
    22.8 +#include "MimeTests.h"
    22.9 +#include "ExpiredSubkeyTests.h"
   22.10  #include "UserIdCollisionTests.h"
   22.11 -#include "ReencryptPlusExtraKeysTests.h"
   22.12 -#include "BlacklistTests.h"
   22.13 -#include "AppleMailTests.h"
   22.14 -#include "MessageTwoPointOhTests.h"
   22.15 +#include "Engine463Tests.h"
   22.16 +#include "BloblistTests.h"
   22.17 +#include "NewUpdateIdAndMyselfTests.h"
   22.18 +#include "I18nTests.h"
   22.19  #include "IdentityListTests.h"
   22.20 -#include "I18nTests.h"
   22.21 -#include "Engine463Tests.h"
   22.22 -#include "DecryptAttachPrivateKeyUntrustedTests.h"
   22.23 +#include "PgpBinaryTests.h"
   22.24 +#include "MistrustUndoTests.h"
   22.25 +#include "SubkeyRatingEvalTests.h"
   22.26 +#include "MessageNullFromTests.h"
   22.27 +#include "LeastCommonDenomColorTests.h"
   22.28 +#include "StringlistTests.h"
   22.29 +#include "PgpListKeysTests.h"
   22.30 +#include "MessageApiTests.h"
   22.31 +#include "EncryptMissingPrivateKeyTests.h"
   22.32 +#include "CaseAndDotAddressTests.h"
   22.33 +#include "UserIDAliasTests.h"
   22.34  #include "BCCTests.h"
   22.35 -#include "LeastColorGroupTests.h"
   22.36  #include "Engine358Tests.h"
   22.37  #include "BlacklistAcceptNewKeyTests.h"
   22.38 -#include "MessageApiTests.h"
   22.39 -#include "StringlistTests.h"
   22.40 +#include "DecryptAttachPrivateKeyUntrustedTests.h"
   22.41 +#include "ReturnMistrustFprTests.h"
   22.42 +#include "BlacklistTests.h"
   22.43 +#include "RevokeRegenAttachTests.h"
   22.44 +#include "PepSubjectReceivedTests.h"
   22.45 +#include "SequenceTests.h"
   22.46  #include "HeaderKeyImportTests.h"
   22.47 +#include "EncryptAttachPrivateKeyTests.h"
   22.48 +#include "ExternalRevokeTests.h"
   22.49 +#include "KeyeditTests.h"
   22.50 +#include "LeastColorGroupTests.h"
   22.51 +#include "DecryptAttachPrivateKeyTrustedTests.h"
   22.52 +#include "CheckRenewedExpiredKeyTrustStatusTests.h"
   22.53 +#include "TrustwordsTests.h"
   22.54 +#include "ReencryptPlusExtraKeysTests.h"
   22.55 +#include "MapAsn1Tests.h"
   22.56 +#include "DecorateTests.h"
   22.57 +#include "MessageTwoPointOhTests.h"
   22.58 +#include "CrashdumpTests.h"
   22.59  #include "StringpairListTests.h"
   22.60 +#include "EncryptForIdentityTests.h"
   22.61  #include "TrustManipulationTests.h"
   22.62 -#include "SignOnlyTests.h"
   22.63 -#include "EncryptAttachPrivateKeyTests.h"
   22.64 -#include "BloblistTests.h"
   22.65 -#include "KeyResetMessageTests.h"
   22.66 -#include "SequenceTests.h"
   22.67 -#include "TrustwordsTests.h"
   22.68 -#include "RevokeRegenAttachTests.h"
   22.69 -#include "CheckRenewedExpiredKeyTrustStatusTests.h"
   22.70 -#include "EncryptMissingPrivateKeyTests.h"
   22.71 -#include "PepSubjectReceivedTests.h"
   22.72 -#include "KeyeditTests.h"
   22.73 -#include "MapAsn1Tests.h"
   22.74 -#include "PgpBinaryTests.h"
   22.75 -#include "DecryptAttachPrivateKeyTrustedTests.h"
   22.76 -#include "MessageNullFromTests.h"
   22.77 -#include "MimeTests.h"
   22.78 -#include "PgpListKeysTests.h"
   22.79 -#include "NewUpdateIdAndMyselfTests.h"
   22.80 -#include "EncryptForIdentityTests.h"
   22.81 -#include "CrashdumpTests.h"
   22.82 -#include "CaseAndDotAddressTests.h"
   22.83 -#include "ExpiredSubkeyTests.h"
   22.84 -#include "LeastCommonDenomColorTests.h"
   22.85 -#include "ExternalRevokeTests.h"
   22.86 -#include "UserIDAliasTests.h"
   22.87 +#include "AppleMailTests.h"
   22.88  
   22.89  
   22.90  const char* SuiteMaker::all_suites[] = {
   22.91 -    "DecorateTests",
   22.92 +    "MimeTests",
   22.93 +    "ExpiredSubkeyTests",
   22.94      "UserIdCollisionTests",
   22.95 -    "ReencryptPlusExtraKeysTests",
   22.96 -    "BlacklistTests",
   22.97 -    "AppleMailTests",
   22.98 -    "MessageTwoPointOhTests",
   22.99 +    "Engine463Tests",
  22.100 +    "BloblistTests",
  22.101 +    "NewUpdateIdAndMyselfTests",
  22.102 +    "I18nTests",
  22.103      "IdentityListTests",
  22.104 -    "I18nTests",
  22.105 -    "Engine463Tests",
  22.106 -    "DecryptAttachPrivateKeyUntrustedTests",
  22.107 +    "PgpBinaryTests",
  22.108 +    "MistrustUndoTests",
  22.109 +    "SubkeyRatingEvalTests",
  22.110 +    "MessageNullFromTests",
  22.111 +    "LeastCommonDenomColorTests",
  22.112 +    "StringlistTests",
  22.113 +    "PgpListKeysTests",
  22.114 +    "MessageApiTests",
  22.115 +    "EncryptMissingPrivateKeyTests",
  22.116 +    "CaseAndDotAddressTests",
  22.117 +    "UserIDAliasTests",
  22.118      "BCCTests",
  22.119 -    "LeastColorGroupTests",
  22.120      "Engine358Tests",
  22.121      "BlacklistAcceptNewKeyTests",
  22.122 -    "MessageApiTests",
  22.123 -    "StringlistTests",
  22.124 +    "DecryptAttachPrivateKeyUntrustedTests",
  22.125 +    "ReturnMistrustFprTests",
  22.126 +    "BlacklistTests",
  22.127 +    "RevokeRegenAttachTests",
  22.128 +    "PepSubjectReceivedTests",
  22.129 +    "SequenceTests",
  22.130      "HeaderKeyImportTests",
  22.131 +    "EncryptAttachPrivateKeyTests",
  22.132 +    "ExternalRevokeTests",
  22.133 +    "KeyeditTests",
  22.134 +    "LeastColorGroupTests",
  22.135 +    "DecryptAttachPrivateKeyTrustedTests",
  22.136 +    "CheckRenewedExpiredKeyTrustStatusTests",
  22.137 +    "TrustwordsTests",
  22.138 +    "ReencryptPlusExtraKeysTests",
  22.139 +    "MapAsn1Tests",
  22.140 +    "DecorateTests",
  22.141 +    "MessageTwoPointOhTests",
  22.142 +    "CrashdumpTests",
  22.143      "StringpairListTests",
  22.144 +    "EncryptForIdentityTests",
  22.145      "TrustManipulationTests",
  22.146 -    "SignOnlyTests",
  22.147 -    "EncryptAttachPrivateKeyTests",
  22.148 -    "BloblistTests",
  22.149 -    "KeyResetMessageTests",
  22.150 -    "SequenceTests",
  22.151 -    "TrustwordsTests",
  22.152 -    "RevokeRegenAttachTests",
  22.153 -    "CheckRenewedExpiredKeyTrustStatusTests",
  22.154 -    "EncryptMissingPrivateKeyTests",
  22.155 -    "PepSubjectReceivedTests",
  22.156 -    "KeyeditTests",
  22.157 -    "MapAsn1Tests",
  22.158 -    "PgpBinaryTests",
  22.159 -    "DecryptAttachPrivateKeyTrustedTests",
  22.160 -    "MessageNullFromTests",
  22.161 -    "MimeTests",
  22.162 -    "PgpListKeysTests",
  22.163 -    "NewUpdateIdAndMyselfTests",
  22.164 -    "EncryptForIdentityTests",
  22.165 -    "CrashdumpTests",
  22.166 -    "CaseAndDotAddressTests",
  22.167 -    "ExpiredSubkeyTests",
  22.168 -    "LeastCommonDenomColorTests",
  22.169 -    "ExternalRevokeTests",
  22.170 -    "UserIDAliasTests",
  22.171 +    "AppleMailTests",
  22.172  };
  22.173  
  22.174  // This file is generated, so magic constants are ok.
  22.175 -int SuiteMaker::num_suites = 44;
  22.176 +int SuiteMaker::num_suites = 45;
  22.177  
  22.178  void SuiteMaker::suitemaker_build(const char* test_class_name, const char* test_home, Test::Suite** test_suite) {
  22.179 -    if (strcmp(test_class_name, "DecorateTests") == 0)
  22.180 -        *test_suite = new DecorateTests(test_class_name, test_home);
  22.181 +    if (strcmp(test_class_name, "MimeTests") == 0)
  22.182 +        *test_suite = new MimeTests(test_class_name, test_home);
  22.183 +    else if (strcmp(test_class_name, "ExpiredSubkeyTests") == 0)
  22.184 +        *test_suite = new ExpiredSubkeyTests(test_class_name, test_home);
  22.185      else if (strcmp(test_class_name, "UserIdCollisionTests") == 0)
  22.186          *test_suite = new UserIdCollisionTests(test_class_name, test_home);
  22.187 -    else if (strcmp(test_class_name, "ReencryptPlusExtraKeysTests") == 0)
  22.188 -        *test_suite = new ReencryptPlusExtraKeysTests(test_class_name, test_home);
  22.189 -    else if (strcmp(test_class_name, "BlacklistTests") == 0)
  22.190 -        *test_suite = new BlacklistTests(test_class_name, test_home);
  22.191 -    else if (strcmp(test_class_name, "AppleMailTests") == 0)
  22.192 -        *test_suite = new AppleMailTests(test_class_name, test_home);
  22.193 -    else if (strcmp(test_class_name, "MessageTwoPointOhTests") == 0)
  22.194 -        *test_suite = new MessageTwoPointOhTests(test_class_name, test_home);
  22.195 +    else if (strcmp(test_class_name, "Engine463Tests") == 0)
  22.196 +        *test_suite = new Engine463Tests(test_class_name, test_home);
  22.197 +    else if (strcmp(test_class_name, "BloblistTests") == 0)
  22.198 +        *test_suite = new BloblistTests(test_class_name, test_home);
  22.199 +    else if (strcmp(test_class_name, "NewUpdateIdAndMyselfTests") == 0)
  22.200 +        *test_suite = new NewUpdateIdAndMyselfTests(test_class_name, test_home);
  22.201 +    else if (strcmp(test_class_name, "I18nTests") == 0)
  22.202 +        *test_suite = new I18nTests(test_class_name, test_home);
  22.203      else if (strcmp(test_class_name, "IdentityListTests") == 0)
  22.204          *test_suite = new IdentityListTests(test_class_name, test_home);
  22.205 -    else if (strcmp(test_class_name, "I18nTests") == 0)
  22.206 -        *test_suite = new I18nTests(test_class_name, test_home);
  22.207 -    else if (strcmp(test_class_name, "Engine463Tests") == 0)
  22.208 -        *test_suite = new Engine463Tests(test_class_name, test_home);
  22.209 -    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyUntrustedTests") == 0)
  22.210 -        *test_suite = new DecryptAttachPrivateKeyUntrustedTests(test_class_name, test_home);
  22.211 +    else if (strcmp(test_class_name, "PgpBinaryTests") == 0)
  22.212 +        *test_suite = new PgpBinaryTests(test_class_name, test_home);
  22.213 +    else if (strcmp(test_class_name, "MistrustUndoTests") == 0)
  22.214 +        *test_suite = new MistrustUndoTests(test_class_name, test_home);
  22.215 +    else if (strcmp(test_class_name, "SubkeyRatingEvalTests") == 0)
  22.216 +        *test_suite = new SubkeyRatingEvalTests(test_class_name, test_home);
  22.217 +    else if (strcmp(test_class_name, "MessageNullFromTests") == 0)
  22.218 +        *test_suite = new MessageNullFromTests(test_class_name, test_home);
  22.219 +    else if (strcmp(test_class_name, "LeastCommonDenomColorTests") == 0)
  22.220 +        *test_suite = new LeastCommonDenomColorTests(test_class_name, test_home);
  22.221 +    else if (strcmp(test_class_name, "StringlistTests") == 0)
  22.222 +        *test_suite = new StringlistTests(test_class_name, test_home);
  22.223 +    else if (strcmp(test_class_name, "PgpListKeysTests") == 0)
  22.224 +        *test_suite = new PgpListKeysTests(test_class_name, test_home);
  22.225 +    else if (strcmp(test_class_name, "MessageApiTests") == 0)
  22.226 +        *test_suite = new MessageApiTests(test_class_name, test_home);
  22.227 +    else if (strcmp(test_class_name, "EncryptMissingPrivateKeyTests") == 0)
  22.228 +        *test_suite = new EncryptMissingPrivateKeyTests(test_class_name, test_home);
  22.229 +    else if (strcmp(test_class_name, "CaseAndDotAddressTests") == 0)
  22.230 +        *test_suite = new CaseAndDotAddressTests(test_class_name, test_home);
  22.231 +    else if (strcmp(test_class_name, "UserIDAliasTests") == 0)
  22.232 +        *test_suite = new UserIDAliasTests(test_class_name, test_home);
  22.233      else if (strcmp(test_class_name, "BCCTests") == 0)
  22.234          *test_suite = new BCCTests(test_class_name, test_home);
  22.235 -    else if (strcmp(test_class_name, "LeastColorGroupTests") == 0)
  22.236 -        *test_suite = new LeastColorGroupTests(test_class_name, test_home);
  22.237      else if (strcmp(test_class_name, "Engine358Tests") == 0)
  22.238          *test_suite = new Engine358Tests(test_class_name, test_home);
  22.239      else if (strcmp(test_class_name, "BlacklistAcceptNewKeyTests") == 0)
  22.240          *test_suite = new BlacklistAcceptNewKeyTests(test_class_name, test_home);
  22.241 -    else if (strcmp(test_class_name, "MessageApiTests") == 0)
  22.242 -        *test_suite = new MessageApiTests(test_class_name, test_home);
  22.243 -    else if (strcmp(test_class_name, "StringlistTests") == 0)
  22.244 -        *test_suite = new StringlistTests(test_class_name, test_home);
  22.245 +    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyUntrustedTests") == 0)
  22.246 +        *test_suite = new DecryptAttachPrivateKeyUntrustedTests(test_class_name, test_home);
  22.247 +    else if (strcmp(test_class_name, "ReturnMistrustFprTests") == 0)
  22.248 +        *test_suite = new ReturnMistrustFprTests(test_class_name, test_home);
  22.249 +    else if (strcmp(test_class_name, "BlacklistTests") == 0)
  22.250 +        *test_suite = new BlacklistTests(test_class_name, test_home);
  22.251 +    else if (strcmp(test_class_name, "RevokeRegenAttachTests") == 0)
  22.252 +        *test_suite = new RevokeRegenAttachTests(test_class_name, test_home);
  22.253 +    else if (strcmp(test_class_name, "PepSubjectReceivedTests") == 0)
  22.254 +        *test_suite = new PepSubjectReceivedTests(test_class_name, test_home);
  22.255 +    else if (strcmp(test_class_name, "SequenceTests") == 0)
  22.256 +        *test_suite = new SequenceTests(test_class_name, test_home);
  22.257      else if (strcmp(test_class_name, "HeaderKeyImportTests") == 0)
  22.258          *test_suite = new HeaderKeyImportTests(test_class_name, test_home);
  22.259 +    else if (strcmp(test_class_name, "EncryptAttachPrivateKeyTests") == 0)
  22.260 +        *test_suite = new EncryptAttachPrivateKeyTests(test_class_name, test_home);
  22.261 +    else if (strcmp(test_class_name, "ExternalRevokeTests") == 0)
  22.262 +        *test_suite = new ExternalRevokeTests(test_class_name, test_home);
  22.263 +    else if (strcmp(test_class_name, "KeyeditTests") == 0)
  22.264 +        *test_suite = new KeyeditTests(test_class_name, test_home);
  22.265 +    else if (strcmp(test_class_name, "LeastColorGroupTests") == 0)
  22.266 +        *test_suite = new LeastColorGroupTests(test_class_name, test_home);
  22.267 +    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyTrustedTests") == 0)
  22.268 +        *test_suite = new DecryptAttachPrivateKeyTrustedTests(test_class_name, test_home);
  22.269 +    else if (strcmp(test_class_name, "CheckRenewedExpiredKeyTrustStatusTests") == 0)
  22.270 +        *test_suite = new CheckRenewedExpiredKeyTrustStatusTests(test_class_name, test_home);
  22.271 +    else if (strcmp(test_class_name, "TrustwordsTests") == 0)
  22.272 +        *test_suite = new TrustwordsTests(test_class_name, test_home);
  22.273 +    else if (strcmp(test_class_name, "ReencryptPlusExtraKeysTests") == 0)
  22.274 +        *test_suite = new ReencryptPlusExtraKeysTests(test_class_name, test_home);
  22.275 +    else if (strcmp(test_class_name, "MapAsn1Tests") == 0)
  22.276 +        *test_suite = new MapAsn1Tests(test_class_name, test_home);
  22.277 +    else if (strcmp(test_class_name, "DecorateTests") == 0)
  22.278 +        *test_suite = new DecorateTests(test_class_name, test_home);
  22.279 +    else if (strcmp(test_class_name, "MessageTwoPointOhTests") == 0)
  22.280 +        *test_suite = new MessageTwoPointOhTests(test_class_name, test_home);
  22.281 +    else if (strcmp(test_class_name, "CrashdumpTests") == 0)
  22.282 +        *test_suite = new CrashdumpTests(test_class_name, test_home);
  22.283      else if (strcmp(test_class_name, "StringpairListTests") == 0)
  22.284          *test_suite = new StringpairListTests(test_class_name, test_home);
  22.285 +    else if (strcmp(test_class_name, "EncryptForIdentityTests") == 0)
  22.286 +        *test_suite = new EncryptForIdentityTests(test_class_name, test_home);
  22.287      else if (strcmp(test_class_name, "TrustManipulationTests") == 0)
  22.288          *test_suite = new TrustManipulationTests(test_class_name, test_home);
  22.289 -    else if (strcmp(test_class_name, "SignOnlyTests") == 0)
  22.290 -        *test_suite = new SignOnlyTests(test_class_name, test_home);
  22.291 -    else if (strcmp(test_class_name, "EncryptAttachPrivateKeyTests") == 0)
  22.292 -        *test_suite = new EncryptAttachPrivateKeyTests(test_class_name, test_home);
  22.293 -    else if (strcmp(test_class_name, "BloblistTests") == 0)
  22.294 -        *test_suite = new BloblistTests(test_class_name, test_home);
  22.295 -    else if (strcmp(test_class_name, "KeyResetMessageTests") == 0)
  22.296 -        *test_suite = new KeyResetMessageTests(test_class_name, test_home);
  22.297 -    else if (strcmp(test_class_name, "SequenceTests") == 0)
  22.298 -        *test_suite = new SequenceTests(test_class_name, test_home);
  22.299 -    else if (strcmp(test_class_name, "TrustwordsTests") == 0)
  22.300 -        *test_suite = new TrustwordsTests(test_class_name, test_home);
  22.301 -    else if (strcmp(test_class_name, "RevokeRegenAttachTests") == 0)
  22.302 -        *test_suite = new RevokeRegenAttachTests(test_class_name, test_home);
  22.303 -    else if (strcmp(test_class_name, "CheckRenewedExpiredKeyTrustStatusTests") == 0)
  22.304 -        *test_suite = new CheckRenewedExpiredKeyTrustStatusTests(test_class_name, test_home);
  22.305 -    else if (strcmp(test_class_name, "EncryptMissingPrivateKeyTests") == 0)
  22.306 -        *test_suite = new EncryptMissingPrivateKeyTests(test_class_name, test_home);
  22.307 -    else if (strcmp(test_class_name, "PepSubjectReceivedTests") == 0)
  22.308 -        *test_suite = new PepSubjectReceivedTests(test_class_name, test_home);
  22.309 -    else if (strcmp(test_class_name, "KeyeditTests") == 0)
  22.310 -        *test_suite = new KeyeditTests(test_class_name, test_home);
  22.311 -    else if (strcmp(test_class_name, "MapAsn1Tests") == 0)
  22.312 -        *test_suite = new MapAsn1Tests(test_class_name, test_home);
  22.313 -    else if (strcmp(test_class_name, "PgpBinaryTests") == 0)
  22.314 -        *test_suite = new PgpBinaryTests(test_class_name, test_home);
  22.315 -    else if (strcmp(test_class_name, "DecryptAttachPrivateKeyTrustedTests") == 0)
  22.316 -        *test_suite = new DecryptAttachPrivateKeyTrustedTests(test_class_name, test_home);
  22.317 -    else if (strcmp(test_class_name, "MessageNullFromTests") == 0)
  22.318 -        *test_suite = new MessageNullFromTests(test_class_name, test_home);
  22.319 -    else if (strcmp(test_class_name, "MimeTests") == 0)
  22.320 -        *test_suite = new MimeTests(test_class_name, test_home);
  22.321 -    else if (strcmp(test_class_name, "PgpListKeysTests") == 0)
  22.322 -        *test_suite = new PgpListKeysTests(test_class_name, test_home);
  22.323 -    else if (strcmp(test_class_name, "NewUpdateIdAndMyselfTests") == 0)
  22.324 -        *test_suite = new NewUpdateIdAndMyselfTests(test_class_name, test_home);
  22.325 -    else if (strcmp(test_class_name, "EncryptForIdentityTests") == 0)
  22.326 -        *test_suite = new EncryptForIdentityTests(test_class_name, test_home);
  22.327 -    else if (strcmp(test_class_name, "CrashdumpTests") == 0)
  22.328 -        *test_suite = new CrashdumpTests(test_class_name, test_home);
  22.329 -    else if (strcmp(test_class_name, "CaseAndDotAddressTests") == 0)
  22.330 -        *test_suite = new CaseAndDotAddressTests(test_class_name, test_home);
  22.331 -    else if (strcmp(test_class_name, "ExpiredSubkeyTests") == 0)
  22.332 -        *test_suite = new ExpiredSubkeyTests(test_class_name, test_home);
  22.333 -    else if (strcmp(test_class_name, "LeastCommonDenomColorTests") == 0)
  22.334 -        *test_suite = new LeastCommonDenomColorTests(test_class_name, test_home);
  22.335 -    else if (strcmp(test_class_name, "ExternalRevokeTests") == 0)
  22.336 -        *test_suite = new ExternalRevokeTests(test_class_name, test_home);
  22.337 -    else if (strcmp(test_class_name, "UserIDAliasTests") == 0)
  22.338 -        *test_suite = new UserIDAliasTests(test_class_name, test_home);
  22.339 +    else if (strcmp(test_class_name, "AppleMailTests") == 0)
  22.340 +        *test_suite = new AppleMailTests(test_class_name, test_home);
  22.341  }
  22.342  
  22.343  void SuiteMaker::suitemaker_buildlist(const char** test_class_names, int num_to_run, const char* test_home, std::vector<Test::Suite*>& test_suites) {
    23.1 --- a/test/src/TestDriver.cc	Mon Dec 24 15:32:27 2018 +0100
    23.2 +++ b/test/src/TestDriver.cc	Wed Jan 23 11:59:43 2019 +0100
    23.3 @@ -15,6 +15,7 @@
    23.4  #include "EngineTestIndividualSuite.h"
    23.5  #include "EngineTestSessionSuite.h"
    23.6  #include "SuiteMaker.h"
    23.7 +#include "pEpTestStatic.h"
    23.8  
    23.9  using namespace std;
   23.10  
   23.11 @@ -38,7 +39,21 @@
   23.12          throw std::runtime_error("Error grabbing current working directory"); 
   23.13  
   23.14      common_test_home = curr_wd + "/pEp_test_home";    
   23.15 +
   23.16 +    // Note: THIS IS BRITTLE. If you're trying on a new platform and it fails, it's because C++ names may be mangled differently
   23.17 +    // and other platforms may have other requirements. Start by checking maximum socket path lengths...
   23.18 +    // We need at least size for 3 chars of unique class dir, 3 chars of test number, 5 chars for "gnupg", for "S.gpg-agent", plus
   23.19 +    // slashes. This is really just because gpg-agent fails on MacOS because of a shorter sun_path max.
   23.20      
   23.21 +    // fixme = "gnupg" needs to be made central
   23.22 +    string keypath_str = "gnupg";
   23.23 +
   23.24 +    if (common_test_home.size() > pEpTestStatic::getAvailablePathChars(keypath_str)) {
   23.25 +        cerr << "Test home path size too long. Please notify the devs that this finally broke." 
   23.26 +             << " In the meantime, try modifying common_test_home here in TestDriver.cc and hope nothing breaks" << endl;
   23.27 +        throw -127;
   23.28 +    }     
   23.29 +
   23.30      EngineTestSuite* test_runner = new EngineTestSuite("MainTestDriver", common_test_home);
   23.31  
   23.32      std::vector<Test::Suite*> suites_to_run;
    24.1 --- a/test/src/engine_tests/DecryptAttachPrivateKeyTrustedTests.cc	Mon Dec 24 15:32:27 2018 +0100
    24.2 +++ b/test/src/engine_tests/DecryptAttachPrivateKeyTrustedTests.cc	Wed Jan 23 11:59:43 2019 +0100
    24.3 @@ -45,40 +45,27 @@
    24.4      // 13A9F97964A2B52520CAA40E51BCA783C065A213    
    24.5      input_key = slurp("test_keys/pub/priv-key-import-test-main_0-0xC065A213_pub.asc");
    24.6      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
    24.7 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
    24.8 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
    24.9  
   24.10      input_key = slurp("test_keys/priv/priv-key-import-test-main_0-0xC065A213_priv.asc");
   24.11      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   24.12 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   24.13 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   24.14  
   24.15      // ensure there's no private key - doesn't work in automated tests, sadly. Uncommon when running script manually.
   24.16      bool has_priv = false;
   24.17 -    // status = contains_priv_key(session, fpr_same_addr_same_uid, &has_priv);
   24.18 -    // if (status == PEP_STATUS_OK && has_priv) {
   24.19 -    //     cout << "SORRY, have to delete keys here to run test correctly..." << endl;
   24.20 -    //     status = delete_keypair(session, fpr_same_addr_same_uid);
   24.21 -    //     if (status == PEP_STATUS_OK) {
   24.22 -    //         has_priv = false;
   24.23 -    //         status = contains_priv_key(session, fpr_same_addr_same_uid, &has_priv);
   24.24 -    //         TEST_ASSERT_MSG((has_priv == false), "has_priv == false");
   24.25 -    //         cout << "Successfully deleted keypair for " << fpr_same_addr_same_uid << " - will now import the public key only" << endl;
   24.26 -    //     }
   24.27 -    //     else
   24.28 -    //         cout << "Warning - delete keypair returned status " << tl_status_string(status) << ". This may or may not be an error, depending on what you expect." << endl;            
   24.29 -    // }
   24.30          
   24.31      // key with same address and user_id
   24.32      // 8AB616A3BD51DEF714B5E688EFFB540C3276D2E5
   24.33      input_key = slurp("test_keys/pub/priv-key-import-test-main_0-0x3276D2E5_pub.asc");
   24.34      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   24.35 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   24.36 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   24.37  
   24.38      
   24.39      cout << "Setting up own identity with default key " << fpr_main_me << endl;
   24.40      // Own identity with default key etc
   24.41      main_me = new_identity(main_addr, fpr_main_me, own_uid, "PrivateKey Import Test");
   24.42      status = set_own_key(session, main_me, fpr_main_me);
   24.43 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   24.44 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   24.45  
   24.46      TEST_ASSERT_MSG((strcmp(main_me->fpr, fpr_main_me) == 0), "strcmp(main_me->fpr, fpr_main_me) == 0");
   24.47      cout << "Done!" << endl << endl;
   24.48 @@ -86,8 +73,8 @@
   24.49      cout << "Setting up sender identities and resetting key trust." << endl;
   24.50      cout << "Same address, same user_id - address: " << main_addr << ", user_id: " << own_uid << ", fpr: " << fpr_same_addr_same_uid << endl;  
   24.51      same_addr_same_uid = new_identity(main_addr, fpr_same_addr_same_uid, own_uid, "PrivateKey Import Test");
   24.52 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK || status == PEP_CANNOT_FIND_IDENTITY), "status == PEP_STATUS_OK || status == PEP_CANNOT_FIND_IDENTITY");
   24.53 -    TEST_ASSERT_MSG(((same_addr_same_uid->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed), "(same_addr_same_uid->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed");
   24.54 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK || status == PEP_CANNOT_FIND_IDENTITY), tl_status_string(status));
   24.55 +    TEST_ASSERT_MSG(((same_addr_same_uid->comm_type & PEP_ct_confirmed) != PEP_ct_confirmed), tl_ct_string(same_addr_same_uid->comm_type));
   24.56  
   24.57      status = key_reset_trust(session, same_addr_same_uid);
   24.58      
   24.59 @@ -107,10 +94,10 @@
   24.60      PEP_decrypt_flags_t flags = 0;
   24.61      char* modified_src = NULL;
   24.62      
   24.63 -    cout << "Trusting personal key for " << same_addr_same_uid->user_id << " and " << same_addr_same_uid->fpr << endl;
   24.64 -    status = trust_personal_key(session, same_addr_same_uid);
   24.65 +    cout << "Trusting own key for " << same_addr_same_uid->user_id << " and " << same_addr_same_uid->fpr << endl;
   24.66 +    status = trust_own_key(session, same_addr_same_uid);
   24.67      cout << "Status is " << tl_status_string(status) << endl;  
   24.68 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   24.69 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   24.70      free(decrypted_text);
   24.71      decrypted_text = NULL;
   24.72  
   24.73 @@ -135,7 +122,7 @@
   24.74                                    &modified_src);
   24.75      
   24.76      cout << "Status: " << tl_status_string(status) << endl;
   24.77 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   24.78 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   24.79  
   24.80      cout << decrypted_text << endl;
   24.81      
    25.1 --- a/test/src/engine_tests/EncryptAttachPrivateKeyTests.cc	Mon Dec 24 15:32:27 2018 +0100
    25.2 +++ b/test/src/engine_tests/EncryptAttachPrivateKeyTests.cc	Wed Jan 23 11:59:43 2019 +0100
    25.3 @@ -56,42 +56,42 @@
    25.4      // 8AB616A3BD51DEF714B5E688EFFB540C3276D2E5
    25.5      input_key = slurp("test_keys/pub/priv-key-import-test-main_0-0x3276D2E5_pub.asc");
    25.6      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
    25.7 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
    25.8 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
    25.9  
   25.10      input_key = slurp("test_keys/priv/priv-key-import-test-main_0-0x3276D2E5_priv.asc");
   25.11      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   25.12 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.13 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.14          
   25.15      // key with same address and user_id (initially untrusted, then trusted)
   25.16      // 359DD8AC87D1F5E4304D08338D7185F180C8CD87
   25.17      input_key = slurp("test_keys/pub/priv-key-import-test-main_1-0x80C8CD87_pub.asc");
   25.18      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   25.19 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.20 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.21  
   25.22      // key with same address and to have different (non-aliased) user_id (initially untrusted, then trusted)
   25.23      // B044B83639E292283A3F6E14C2E64B520B74809C
   25.24      input_key = slurp("test_keys/pub/priv-key-import-test-main_2-0x0B74809C_pub.asc");
   25.25      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   25.26 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.27 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.28  
   25.29      // key with different address to have same user_id (initially untrusted, then trusted)
   25.30      // C52911EBA0D34B0F549594A15A7A363BD11252C9
   25.31      input_key = slurp("test_keys/pub/priv-key-import-test-other_0-0xD11252C9_pub.asc");
   25.32      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   25.33 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.34 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.35          
   25.36      // key with different address to have different user_id (initially untrusted, then trusted)
   25.37      // 567212EFB8A3A76B1D32B9565F45BEA9C785F20A
   25.38      input_key = slurp("test_keys/pub/priv-key-import-test-other_1-0xC785F20A_pub.asc");
   25.39      status = import_key(session, input_key.c_str(), input_key.length(), NULL);
   25.40 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.41 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.42      cout << "Done!" << endl << endl;
   25.43      
   25.44      cout << "Setting up own identity with default key " << fpr_main_me << endl;
   25.45      // Own identity with default key etc
   25.46      main_me = new_identity(main_addr, fpr_main_me, own_uid, "PrivateKey Import Test");
   25.47      status = set_own_key(session, main_me, fpr_main_me);
   25.48 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.49 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.50  
   25.51      TEST_ASSERT_MSG((strcmp(main_me->fpr, fpr_main_me) == 0), "strcmp(main_me->fpr, fpr_main_me) == 0");
   25.52      cout << "Done!" << endl << endl;
   25.53 @@ -161,9 +161,9 @@
   25.54      // Case 2:
   25.55      // Same address, same_user_id, trusted
   25.56      cout << "Case 2: Same address, same user_id, trusted" << endl;
   25.57 -    status = trust_personal_key(session, same_addr_same_uid);
   25.58 +    status = trust_own_key(session, same_addr_same_uid);
   25.59      cout << "Trust personal key for " << same_addr_same_uid << " gives status " << tl_status_string(status) << " (" << status << ")" << endl;
   25.60 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.61 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.62      message* enc_same_addr_same_uid_trusted = NULL;
   25.63      status = encrypt_message_and_add_priv_key(session,
   25.64                                                msg_same_addr_same_uid,
   25.65 @@ -173,7 +173,7 @@
   25.66                                                0);
   25.67  
   25.68      cout << "Case 2 Status: " << tl_status_string(status) << endl;
   25.69 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.70 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.71      cout << "PASS!" << endl;
   25.72  
   25.73      // Case 3:
   25.74 @@ -197,8 +197,8 @@
   25.75      // Case 4:
   25.76      // Different address, same user_id, trusted
   25.77      cout << "Case 4: Different address, same user_id, trusted" << endl;
   25.78 -    status = trust_personal_key(session, diff_addr_same_uid);
   25.79 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.80 +    status = trust_own_key(session, diff_addr_same_uid);
   25.81 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.82      message* enc_diff_addr_same_uid_trusted = NULL;
   25.83      status = encrypt_message_and_add_priv_key(session,
   25.84                                                msg_diff_addr_same_uid,
   25.85 @@ -233,7 +233,7 @@
   25.86      // Same address, different user_id, trusted
   25.87      cout << "Case 6: Same address, different user_id, trusted" << endl;        
   25.88      status = trust_personal_key(session, same_addr_diff_uid);
   25.89 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.90 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   25.91      message* enc_same_addr_diff_uid_trusted = NULL;
   25.92      status = encrypt_message_and_add_priv_key(session,
   25.93                                                msg_same_addr_diff_uid,
   25.94 @@ -268,7 +268,7 @@
   25.95      // Different address, different user_id, trusted
   25.96      cout << "Case 8: Different address, different user_id, trusted" << endl;    
   25.97      status = trust_personal_key(session, diff_addr_diff_uid);
   25.98 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   25.99 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
  25.100      message* enc_diff_addr_diff_uid_trusted = NULL;
  25.101      status = encrypt_message_and_add_priv_key(session,
  25.102                                                msg_diff_addr_diff_uid,
    26.1 --- a/test/src/engine_tests/LeastCommonDenomColorTests.cc	Mon Dec 24 15:32:27 2018 +0100
    26.2 +++ b/test/src/engine_tests/LeastCommonDenomColorTests.cc	Wed Jan 23 11:59:43 2019 +0100
    26.3 @@ -68,12 +68,12 @@
    26.4      PEP_decrypt_flags_t flags;
    26.5      
    26.6      status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
    26.7 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
    26.8 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
    26.9      TEST_ASSERT_MSG((msg_ptr), "msg_ptr");
   26.10  
   26.11      flags = 0;
   26.12      status = decrypt_message(session, msg_ptr, &dest_msg, &keylist, &rating, &flags);
   26.13 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   26.14 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   26.15      TEST_ASSERT_MSG((dest_msg), "dest_msg");
   26.16      /* message is signed and no recip is mistrusted... */
   26.17      TEST_ASSERT_MSG((color_from_rating(rating) == PEP_color_yellow), "color_from_rating(rating) == PEP_color_yellow");
   26.18 @@ -86,12 +86,12 @@
   26.19      
   26.20      /* re-evaluate rating, counting on optional fields */
   26.21      status = re_evaluate_message_rating(session, dest_msg, NULL, PEP_rating_undefined, &rating);
   26.22 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   26.23 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   26.24      TEST_ASSERT_MSG((color_from_rating(rating) == PEP_color_yellow), "color_from_rating(rating) == PEP_color_yellow");
   26.25  
   26.26      /* re-evaluate rating, without optional fields */
   26.27      status = re_evaluate_message_rating(session, dest_msg, keylist, decrypt_rating, &rating);
   26.28 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   26.29 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   26.30      TEST_ASSERT_MSG((color_from_rating(rating) == PEP_color_yellow), "color_from_rating(rating) == PEP_color_yellow");
   26.31  
   26.32      /* Ok, now mistrust one recip */
   26.33 @@ -99,12 +99,12 @@
   26.34  
   26.35      /* re-evaluate rating, counting on optional fields */
   26.36      status = re_evaluate_message_rating(session, dest_msg, NULL, PEP_rating_undefined, &rating);
   26.37 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   26.38 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   26.39      TEST_ASSERT_MSG((color_from_rating(rating) == PEP_color_red), "color_from_rating(rating) == PEP_color_red");
   26.40  
   26.41      /* re-evaluate rating, without optional fields */
   26.42      status = re_evaluate_message_rating(session, dest_msg, keylist, decrypt_rating, &rating);
   26.43 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   26.44 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   26.45      TEST_ASSERT_MSG((color_from_rating(rating) == PEP_color_red), "color_from_rating(rating) == PEP_color_red");
   26.46  
   26.47      free_message(dest_msg);
   26.48 @@ -117,7 +117,7 @@
   26.49      rating = PEP_rating_unreliable;
   26.50  
   26.51      status = mime_decode_message(mailtext.c_str(), mailtext.length(), &msg_ptr);
   26.52 -    TEST_ASSERT_MSG((status == PEP_STATUS_OK), "status == PEP_STATUS_OK");
   26.53 +    TEST_ASSERT_MSG((status == PEP_STATUS_OK), tl_status_string(status));
   26.54      TEST_ASSERT_MSG((msg_ptr), "msg_ptr");
   26.55      flags = 0;
   26.56      status = decrypt_message(session, msg_ptr, &dest_msg, &keylist, &rating, &flags);
   26.57 @@ -137,4 +137,6 @@
   26.58      dest_msg = nullptr;
   26.59      keylist = nullptr;
   26.60      rating = PEP_rating_unreliable;
   26.61 +
   26.62 +    TEST_ASSERT(true);
   26.63  }
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/test/src/engine_tests/SubkeyRatingEvalTests.cc	Wed Jan 23 11:59:43 2019 +0100
    27.3 @@ -0,0 +1,179 @@
    27.4 +// This file is under GNU General Public License 3.0
    27.5 +// see LICENSE.txt
    27.6 +
    27.7 +#include <stdlib.h>
    27.8 +#include <string>
    27.9 +
   27.10 +#include "pEpEngine.h"
   27.11 +
   27.12 +#include <cpptest.h>
   27.13 +#include "test_util.h"
   27.14 +
   27.15 +#include "EngineTestIndividualSuite.h"
   27.16 +#include "SubkeyRatingEvalTests.h"
   27.17 +
   27.18 +using namespace std;
   27.19 +
   27.20 +SubkeyRatingEvalTests::SubkeyRatingEvalTests(string suitename, string test_home_dir) :
   27.21 +    EngineTestIndividualSuite::EngineTestIndividualSuite(suitename, test_home_dir) {
   27.22 +
   27.23 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_no_es"),
   27.24 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_no_es)));
   27.25 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_weak_s"),
   27.26 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_weak_s)));    
   27.27 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_ecc_s"),
   27.28 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_ecc_s)));
   27.29 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_weak_e_strong_ecc_se"),
   27.30 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_weak_e_strong_ecc_se)));
   27.31 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_bad_es"),
   27.32 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_bad_es)));
   27.33 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_bad_e"),
   27.34 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_bad_e)));
   27.35 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_bad_s_ecc_e"),
   27.36 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_bad_s_ecc_e)));    
   27.37 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_revoked_sign_no_alt"),
   27.38 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_revoked_sign_no_alt)));    
   27.39 +    add_test_to_suite(std::pair<std::string, void (Test::Suite::*)()>(string("SubkeyRatingEvalTests::check_subkey_rating_eval_revoked_e_with_alt"),
   27.40 +        static_cast<Func>(&SubkeyRatingEvalTests::check_subkey_rating_eval_revoked_e_with_alt)));            
   27.41 +}
   27.42 +
   27.43 +// pub   rsa2048 2019-01-21 [CA]
   27.44 +//       F0D03C842C0770C2C2A9FEAF2A1ED9814929DC45
   27.45 +// uid           [ unknown] Subkey Check 0 <subkey_select_0@darthmama.cool>
   27.46 +// 
   27.47 +void SubkeyRatingEvalTests::check_subkey_rating_eval_no_es() {
   27.48 +    slurp_and_import_key(session, "test_keys/pub/subkey_select_0-0x4929DC45_pub.asc");
   27.49 +    PEP_comm_type ct = PEP_ct_unknown;
   27.50 +    PEP_STATUS status = get_key_rating(session, "F0D03C842C0770C2C2A9FEAF2A1ED9814929DC45", &ct);
   27.51 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
   27.52 +    TEST_ASSERT_MSG(ct = PEP_ct_key_b0rken, tl_ct_string(ct));
   27.53 +    TEST_ASSERT(true);
   27.54 +}
   27.55 +
   27.56 +// pub   rsa2048 2019-01-21 [CEA]
   27.57 +//       918AF6E986F39B630541E10DF5F7FA35F2BFF59E
   27.58 +// uid           [ unknown] Subkey Check 1 <subkey_select_1@darthmama.cool>
   27.59 +// sub   rsa1024 2019-01-21 [S]
   27.60 +// 
   27.61 +void SubkeyRatingEvalTests::check_subkey_rating_eval_weak_s() {
   27.62 +    slurp_and_import_key(session, "test_keys/pub/subkey_select_1-0xF2BFF59E_pub.asc");
   27.63 +    PEP_comm_type ct = PEP_ct_unknown;
   27.64 +    PEP_STATUS status = get_key_rating(session, "918AF6E986F39B630541E10DF5F7FA35F2BFF59E", &ct);
   27.65 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
   27.66 +    TEST_ASSERT_MSG(ct = PEP_ct_OpenPGP_weak_unconfirmed, tl_ct_string(ct));
   27.67 +    TEST_ASSERT(true);
   27.68 +}    
   27.69 +
   27.70 +// pub   rsa2048 2019-01-21 [CEA]
   27.71 +//       8894202E3D791C95560058BD77676BACBAD7800C
   27.72 +// uid           [ unknown] Subkey Check 2 <subkey_select_2@darthmama.cool>
   27.73 +// sub   ed25519 2019-01-21 [S]
   27.74 +// 
   27.75 +void SubkeyRatingEvalTests::check_subkey_rating_eval_ecc_s() {
   27.76 +    slurp_and_import_key(session, "test_keys/pub/subkey_select_2-0xBAD7800C_pub.asc");
   27.77 +    PEP_comm_type ct = PEP_ct_unknown;
   27.78 +    PEP_STATUS status = get_key_rating(session, "8894202E3D791C95560058BD77676BACBAD7800C", &ct);
   27.79 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
   27.80 +    TEST_ASSERT_MSG(ct = PEP_ct_OpenPGP_unconfirmed, tl_ct_string(ct));
   27.81 +    TEST_ASSERT(true);
   27.82 +}
   27.83 +
   27.84 +// pub   rsa2048 2019-01-21 [CA]
   27.85 +//       5EA5F7F71BB39B4F7924D1E8D11C676134F44C02
   27.86 +// uid           [ unknown] Subkey Check 3 <subkey_select_3@darthmama.cool>
   27.87 +// sub   ed25519 2019-01-21 [S]
   27.88 +// sub   cv25519 2019-01-21 [E]
   27.89 +// sub   rsa1024 2019-01-21 [E]
   27.90 +//
   27.91 +void SubkeyRatingEvalTests::check_subkey_rating_eval_weak_e_strong_ecc_se() {
   27.92 +    slurp_and_import_key(session, "test_keys/pub/subkey_select_3-0x34F44C02_pub.asc");
   27.93 +    PEP_comm_type ct = PEP_ct_unknown;
   27.94 +    PEP_STATUS status = get_key_rating(session, "5EA5F7F71BB39B4F7924D1E8D11C676134F44C02", &ct);
   27.95 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
   27.96 +    TEST_ASSERT_MSG(ct = PEP_ct_OpenPGP_weak_unconfirmed, tl_ct_string(ct));
   27.97 +    TEST_ASSERT(true);
   27.98 +}
   27.99 +
  27.100 +// pub   rsa512 2019-01-22 [SC]
  27.101 +//       70376BC88DE2DAB4BEF831B65FD6F65326F88D0B
  27.102 +// uid           [ unknown] Weak RSA Key <crappykey_0@darthmama.cool>
  27.103 +// sub   rsa512 2019-01-22 [E]
  27.104 +// 
  27.105 +void SubkeyRatingEvalTests::check_subkey_rating_eval_bad_es() {
  27.106 +    slurp_and_import_key(session, "test_keys/pub/crappykey_0-26F88D0B_pub.asc");
  27.107 +    PEP_comm_type ct = PEP_ct_unknown;
  27.108 +    PEP_STATUS status = get_key_rating(session, "70376BC88DE2DAB4BEF831B65FD6F65326F88D0B", &ct);
  27.109 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.110 +    TEST_ASSERT_MSG(ct = PEP_ct_key_too_short, tl_ct_string(ct));
  27.111 +    TEST_ASSERT(true);
  27.112 +}
  27.113 +
  27.114 +// pub   rsa512 2019-01-22 [C]
  27.115 +//       F712B88AF525E4E32A2A24BCD1B86137C508F2B1
  27.116 +// uid           [ unknown] Weak RSA Key <crappykey_1@darthmama.cool>
  27.117 +// sub   rsa512 2019-01-22 [E]
  27.118 +// sub   rsa2048 2019-01-22 [S]
  27.119 +// 
  27.120 +void SubkeyRatingEvalTests::check_subkey_rating_eval_bad_e() {
  27.121 +    slurp_and_import_key(session, "test_keys/pub/crappykey_1-0xC508F2B1_pub.asc");
  27.122 +    PEP_comm_type ct = PEP_ct_unknown;
  27.123 +    PEP_STATUS status = get_key_rating(session, "F712B88AF525E4E32A2A24BCD1B86137C508F2B1", &ct);
  27.124 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.125 +    TEST_ASSERT_MSG(ct = PEP_ct_key_too_short, tl_ct_string(ct));
  27.126 +    TEST_ASSERT(true);
  27.127 +}
  27.128 +
  27.129 +// pub   rsa512 2019-01-22 [SC]
  27.130 +//       18544492055207B2936BB215325776FBC027262F
  27.131 +// uid           [ unknown] Weak RSA Key <crappykey_2@darthmama.cool>
  27.132 +// sub   cv25519 2019-01-22 [E]
  27.133 +//
  27.134 +void SubkeyRatingEvalTests::check_subkey_rating_eval_bad_s_ecc_e() {
  27.135 +    slurp_and_import_key(session, "test_keys/pub/crappykey_2-0xC027262F_pub.asc");
  27.136 +    PEP_comm_type ct = PEP_ct_unknown;
  27.137 +    PEP_STATUS status = get_key_rating(session, "18544492055207B2936BB215325776FBC027262F", &ct);
  27.138 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.139 +    TEST_ASSERT_MSG(ct = PEP_ct_key_too_short, tl_ct_string(ct));
  27.140 +    TEST_ASSERT(true);
  27.141 +}    
  27.142 +
  27.143 +// pub   rsa2048 2019-01-21 [CEA]
  27.144 +//       1E0D278644E2E293A9E953D9AC97F67F6E6C7B8A
  27.145 +// uid           [ unknown] Subkey Check 4 <subkey_select_4@darthmama.cool>
  27.146 +// The following key was revoked on 2019-01-22 by RSA key AC97F67F6E6C7B8A Subkey Check 4 <subkey_select_4@darthmama.cool>
  27.147 +// ssb  ed25519/7A03BDF88893985F
  27.148 +//      created: 2019-01-22  revoked: 2019-01-22  usage: S   
  27.149 +// [ unknown] (1). Subkey Check 4 <subkey_select_4@darthmama.cool>
  27.150 +//
  27.151 +void SubkeyRatingEvalTests::check_subkey_rating_eval_revoked_sign_no_alt() {
  27.152 +    slurp_and_import_key(session, "test_keys/pub/subkey_select_4-0x6E6C7B8A_pub.asc");
  27.153 +    PEP_comm_type ct = PEP_ct_unknown;
  27.154 +    PEP_STATUS status = get_key_rating(session, "1E0D278644E2E293A9E953D9AC97F67F6E6C7B8A", &ct);
  27.155 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.156 +    TEST_ASSERT_MSG(ct = PEP_ct_key_revoked, tl_ct_string(ct));
  27.157 +    TEST_ASSERT(true);
  27.158 +}    
  27.159 +
  27.160 +// pub   rsa2048 2019-01-21 [SCA]
  27.161 +//       A2C00B12660CCB5759E6BF1854315D29D106E693
  27.162 +// uid           [ unknown] Subkey Check 5 <subkey_select_5@darthmama.cool>
  27.163 +// sub   cv25519 2019-01-22 [E]
  27.164 +//
  27.165 +// sec  rsa2048/54315D29D106E693
  27.166 +//      created: 2019-01-21  expires: never       usage: SCA 
  27.167 +//      trust: unknown       validity: unknown
  27.168 +// The following key was revoked on 2019-01-22 by RSA key 54315D29D106E693 Subkey Check 5 <subkey_select_5@darthmama.cool>
  27.169 +// ssb  rsa2048/B16DED0A115801B4
  27.170 +//      created: 2019-01-22  revoked: 2019-01-22  usage: E   
  27.171 +// ssb  cv25519/01B398B420DC3B57
  27.172 +//      created: 2019-01-22  expires: never       usage: E   
  27.173 +// [ unknown] (1). Subkey Check 5 <subkey_select_5@darthmama.cool>
  27.174 +//
  27.175 +void SubkeyRatingEvalTests::check_subkey_rating_eval_revoked_e_with_alt() {
  27.176 +    slurp_and_import_key(session, "test_keys/pub/subkey_select_5-0xD106E693_pub.asc");
  27.177 +    PEP_comm_type ct = PEP_ct_unknown;
  27.178 +    PEP_STATUS status = get_key_rating(session, "A2C00B12660CCB5759E6BF1854315D29D106E693", &ct);
  27.179 +    TEST_ASSERT_MSG(status == PEP_STATUS_OK, tl_status_string(status));
  27.180 +    TEST_ASSERT_MSG(ct = PEP_ct_OpenPGP_unconfirmed, tl_ct_string(ct));
  27.181 +    TEST_ASSERT(true);
  27.182 +}    
    28.1 --- a/test/src/engine_tests/TrustManipulationTests.cc	Mon Dec 24 15:32:27 2018 +0100
    28.2 +++ b/test/src/engine_tests/TrustManipulationTests.cc	Wed Jan 23 11:59:43 2019 +0100
    28.3 @@ -88,6 +88,7 @@
    28.4      cout << "Hoorah, we now do not trust key 2. (We never liked key 2 anyway.)" << endl;
    28.5      cout << "Now we call update_identity to see what gifts it gives us (should be key 1 with key 1's initial trust.)" << endl;    
    28.6      status = update_identity(session, user);
    28.7 +    TEST_ASSERT_MSG((user->fpr), "user->fpr");
    28.8      TEST_ASSERT_MSG((strcmp(user->fpr, keypair1) == 0), "strcmp(user->fpr, keypair1) == 0");
    28.9      TEST_ASSERT_MSG((user->comm_type == PEP_ct_OpenPGP_unconfirmed), "user->comm_type == PEP_ct_OpenPGP_unconfirmed");
   28.10      cout << "Yup, got key 1, and the trust status is PEP_ct_OpenPGP_unconfirmed." << endl;
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/test/src/pEpTestStatic.cc	Wed Jan 23 11:59:43 2019 +0100
    29.3 @@ -0,0 +1,30 @@
    29.4 +#include <stdlib.h>
    29.5 +#include <sys/un.h>
    29.6 +
    29.7 +#include "pEpTestStatic.h"
    29.8 +#include <math.h>
    29.9 +#include <string>
   29.10 +
   29.11 +using namespace std;
   29.12 +
   29.13 +size_t pEpTestStatic::sun_path_size = 0;
   29.14 +size_t pEpTestStatic::available_path_chars = 0;
   29.15 +
   29.16 +const size_t pEpTestStatic::classname_chars = 6;
   29.17 +const size_t pEpTestStatic::testnum_path_chars = 4;
   29.18 +const size_t pEpTestStatic::max_test_num = pow(10, pEpTestStatic::testnum_path_chars) - 1;
   29.19 +
   29.20 +size_t pEpTestStatic::getMaxPathSize() {
   29.21 +    if (pEpTestStatic::sun_path_size == 0) {
   29.22 +        struct sockaddr_un s;
   29.23 +        pEpTestStatic::sun_path_size = sizeof(s.sun_path);
   29.24 +    }
   29.25 +    return pEpTestStatic::sun_path_size;
   29.26 +}
   29.27 +
   29.28 +size_t pEpTestStatic::getAvailablePathChars(string keypath_str) {
   29.29 +    if (pEpTestStatic::available_path_chars == 0) {
   29.30 +        available_path_chars = pEpTestStatic::getMaxPathSize() - classname_chars - testnum_path_chars - keypath_str.size() - 4; // slashes
   29.31 +    }
   29.32 +    return pEpTestStatic::available_path_chars;
   29.33 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/test/test_keys/priv/crappykey_0-26F88D0B_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    30.3 @@ -0,0 +1,20 @@
    30.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    30.5 +
    30.6 +lPgEXEbjwgECAKrQi4nib3fj2QJEFB21fxYXSH0AP48OrK5am/fHIZnorQGQInVE
    30.7 +7/Z3DWLguO6JVGgL22T4HQyHFhq4PCed0r0AEQEAAQAB/R75v3wrJFSk7Gr1RoKW
    30.8 +saujYEFOxLfgDN93TfZSVZ0PoPLMSuuACVlJnisolvy+qzO43Ijur0h5u9NCs4fR
    30.9 +tx8BAL3634H04e01CgDb0IzOh8B0yZOxZT838T+DzOaA4NyHAQDmLKv1bhbClDZ8
   30.10 +xSCEwfTOMtLz0Ne893hU8novnC2LmwD6A68+ErYGMWXZBr4Hf00Nrfxqidh/AIMm
   30.11 +H6ZwLj278tRYzLQpV2VhayBSU0EgS2V5IDxjcmFwcHlrZXlfMEBkYXJ0aG1hbWEu
   30.12 +Y29vbD6IewQTAQIAJQUCXEbjwgUJAAAAAAIbAwYLAwcICQoGFQIICQoBBBYBAgAC
   30.13 +GQEACgkQX9b2Uyb4jQuJ/QH/Yub9iPjUXun8rHcerpT+44MeV5kA/N4HeQy8Ucdn
   30.14 +t5v+Y30HelR+NKtHgM3N9WlfnW0p3T9Gh1+huOxbuXOnY5z4BFxG48IBAgC6RCV1
   30.15 +28OxUGyMTu6ezqYB5ukTphHgEqPy7aI73EgxI7knLwGCSonliFaevk28GBiqssKZ
   30.16 +a4/1Xod/EuOsSgzFABEBAAEAAf4oZCmpZpgHhdScEmu9RTuLcwq854i9yd0Ci1Rg
   30.17 +XbLL8L/gae2bzzToknCZ00VqihWuw4dMqreV+HptAc2VetnbAQDQRgK1HO5ZeVYV
   30.18 ++Cz0pM/sAo/eP4QXFo2/bJvGqB2HYwEA5PMeOrq2N5P5F6NRkQtm5s/VnNMiohme
   30.19 +ps9xDyQIN7cA/0uYDVxvxMF3DqMDsa+LQ2a1Pz4ZoMJRnMv76bZYQ00DUyGIXwQY
   30.20 +AQIACQUCXEbjwgIbDAAKCRBf1vZTJviNC4O3AgChC8ynK4r5FjXr3pgQMffw3VPI
   30.21 +sGgUyZGkTiOzRvgla2vnm7JBackX0zgWYeKYT91Z1YvUAgaXsOtg5+E/6/tK
   30.22 +=7Xzk
   30.23 +-----END PGP PRIVATE KEY BLOCK-----
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/test/test_keys/priv/crappykey_1-0xC508F2B1_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    31.3 @@ -0,0 +1,49 @@
    31.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    31.5 +
    31.6 +lPgEXEblSgECANCN0ls7KiHjDvhNtjEXubECaeG6WUWyiVjylfGd5C3DkCpPw62j
    31.7 +C+5I5iTAwWqhgCYFXx2Taa5bZfxhkyc5sN0AEQEAAQAB/RGEP+1SuFS1Tf4UBN/1
    31.8 +tq6D3eHMNZBRkRCr+2UaVl5zfjgLByh089KOTRkhcMmFRug+GgFkoPYkwNEY9A83
    31.9 +Pj8BAON6co/3W+hfgFlQ3RVvHHtiUvr0crrpY3spzGqNuMtTAQDqs/H7QLO4f1Be
   31.10 +KSK3ZuEDfA1BU6z6ojG0Xo6vz+E9DwEAtNQlExTHD7bnPE81Y2iUmPe8v+MlPXr9
   31.11 +Q343n58EnJdQF7QpV2VhayBSU0EgS2V5IDxjcmFwcHlrZXlfMUBkYXJ0aG1hbWEu
   31.12 +Y29vbD6IkgQTAQgAPAUJAAAAAAYLAwcICQoGFQIICQoBBBYBAgACGQEWIQT3EriK
   31.13 +9SXk4yoqJLzRuGE3xQjysQUCXEbmRQIbAQAKCRDRuGE3xQjysdbTAf9aljQ/Yin9
   31.14 +nHuCp36NSJ6Pz0ojFH4U/X9bdg0ObJMy9nB2kq52dToQVqAAeCrNoM72nUdYpMNK
   31.15 +/gjUkAuZWJYCnPgEXEblSgECAKJ6vLeL3tz58A5Rp+xe/EfE1o/N3P3/75c2ESDS
   31.16 +xQZS4E0zoZaQGOcdbhKwTAyhGqVUNaz29Fh6P2Sx1XCMAiEAEQEAAQAB/A3Dj3qO
   31.17 +AQBftOgFn0/NARqUUGfItOyYcoOw+xT4fePJ3XPzmUoYpvnnK0KG6OjrQp7Xl7ua
   31.18 +dG9T4fB+gVJluTUBAMq19UtJyqzsLBNOSSDfEiULc5i19guLqyeK1/F23RYdAQDN
   31.19 +MUnUsbw1KZzQH6labVuFJEhz9m4WnEMKOw6R6ahM1QEAgzMDoKgw1Jk9qS7cCgtv
   31.20 +XfJMs+60tW2JLcxW/r2VPatSWIhfBBgBAgAJBQJcRuVKAhsMAAoJENG4YTfFCPKx
   31.21 +vJ0B/2UpjsZ2rfUzz4fL+i6xV5hLLtuGxfTmcSDCYxUO6oBSFixYOCKLJ8Pj4PPd
   31.22 +Xk2WwAR/46hX7RiTwKG4VdwlzhCdA5gEXEbmTQEIAN9yhr8bxHoO0UOcaer6bHnw
   31.23 +dJgNmnqpTprFy6/dQk0e5WQsSndqtjhbcM1bVPvtBN9TRNu2V5KskHkIGi9hT6ti
   31.24 +nwb8RpiMmP2IqBB4TG775dDZFoPCIUgT2N9ttHMmEV5z1T3ihFrRZMgeK2tjFgY7
   31.25 +prLm8SPJYy8OHLXtZ1pgjGq/lfWr9FHi+aRPeS+kacSe5kbJdiBrTjQ2V/yXdEUJ
   31.26 +mX65YjFLfh7/mWueMG1weyyM50EjTV/iD+5qLunYgU0KIeMwPEjqlGrj0JSNjhQL
   31.27 +4W3SWK0B2tu2zhT5BD+u0XDug+ZVR1n09HCcE95/BqIqpCf5TJxHswUqLH25dGkA
   31.28 +EQEAAQAH/RnnT3qpL+pMfHL/l4HPnTK3rvSPoyh0JzInGvlcx5pkKgimX82fN9ep
   31.29 +thaAb4YzEH0JTLLB3T4aNjdpuotilxdRvAjVxyNZLUU7Cey63XWCSz6eZA9LOot+
   31.30 +DYa9U42DzMCr4f0mHNzgaHQQl00ANCXt1WHpBux0pMRoOOjYSEKANmKpaU54QHS5
   31.31 +BfIL/7ZgFEayt5jtXsN41La69UvchhqX1OlxcT6gZP84V5cBMn9iom/bjwNMt+RN
   31.32 +8tRhYUh/QvlIziH6h1+/jtAeFYe/f2cVEqS0sGSAA3G8Ng2gVKDaZippOWYCGskD
   31.33 +Iv3V5Dqdzo0Lr1CdXuZG6BYw8OS4fTkEAO2aYYfIQCQrJCvSzPK9TZJ1pJ2+Wznf
   31.34 +rGcbt1KDi9IYsSLB95FM6P0dVBxeQMVcBfh5k5xz5QMBI4uaV80OeG+mZ/vXAWVW
   31.35 +ZamJiYJUANxiJd1R2vdoLiOEu88jqEOADcvAtYymEouAhViklmduwRoRiy7VlGBH
   31.36 +89P/U3Muz4ZlBADwv49v2OUAL1JMqXcCbsZIe03Wc+CofM3sr+Iim8ZF3GwolrQC
   31.37 +7WTB4gkRFK8YdhOIObRfceM49ziF5qf3jWtxLO71uA6mFG+RyLVHKjm7Mb1BBVzI
   31.38 +Wm3KLxR6BSp3a+DfyZ2abfOOisblZ7+4UFYv/oMbv+oexCs473bS/tdDtQQA0wtF
   31.39 +OlXQ0EvidXbNG3urK6o2imOiSlRL3e41CkfkbLS7e3t5mgbMfP73UVNVDf2xFo0Y
   31.40 +vp5urVMFs4HolLe/it9t23G1k8OzKoAVj8inOetImGcNbkq1AJo8LxTIgSNnAllP
   31.41 +z0An+8fy4iN8v3CIaEQDSWstIm/EWP0+zKHwPCs9BYkBrAQYAQgAIBYhBPcSuIr1
   31.42 +JeTjKiokvNG4YTfFCPKxBQJcRuZNAhsCAUAJENG4YTfFCPKxwHQgBBkBCAAdFiEE
   31.43 +RGu+bZeUOk6WERPaRphZFzO/xKQFAlxG5k0ACgkQRphZFzO/xKSCpwgAvKNwZHlT
   31.44 +APkILWmappLE3r99hPfWVAE7p3i69T8rSf/7VhGQiOpFyrw6u/BGVSWEQ+av0NdQ
   31.45 +IsxHCHu0fmV4PIhL8sRE2sP0/0yr6vdriJA5Bha43dv2Iy/EIK4oZ2xwNhPL0l9W
   31.46 +w4d1tr1hX50TBoo0nV3qH6AYHYAebwGCghMhEkeVxH8PzAKnh+qM8f8XpwaOAVmF
   31.47 +Rolg7GCNuDzNl07cyGkVcAqy/lsRNAEow+y3SA6UhmbtDoH2qTYOqYHh3Ntav9n5
   31.48 +rTjwumiLLpbDNnIEnt2rIED48d3krokt/8kSNW1FXaybca51vA0r7m43UycutEJ9
   31.49 +A4fEKzoHeGZkdKdqAgClDYMTn8TgJd01MSlkwhsqqeniG/dEU0ZCptOaYs2GsGBo
   31.50 +byz69d5LKTqcrEbuafP5MXilLOSQkcfPAxli7j0B
   31.51 +=TUJ0
   31.52 +-----END PGP PRIVATE KEY BLOCK-----
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/test/test_keys/priv/crappykey_2-0xC027262F_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    32.3 @@ -0,0 +1,18 @@
    32.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    32.5 +
    32.6 +lPgEXEblegECAKrUcuK2FN/qr6tg0OK4IpDky/kJExGaLGGds2LNqSTuTPCHCCQ/
    32.7 +2gbxFYS60M8oaXpax+EWI4sydMzQR4qXo10AEQEAAQAB/RVGHsaH+WKHRfg4Nts9
    32.8 +JiTYMWSikirbgdJoQro3tWxBQscwoD3fjvzM8QQ90uAI88PxckYr2HCr2X4rNdUt
    32.9 +jMsBAMQjgSRjk9ihXeJ3iR/TlY8woiBwnMYl+diahjghGGZ7AQDe94svWLqIW1YC
   32.10 +MSlAAQVtFnoeGKCt+eP+O5VLG0miBwD+PfDp9sJ4EOU07/QFZ8dF7W/LWj/ByzuM
   32.11 +Gccl9jgeMBZPW7QpV2VhayBSU0EgS2V5IDxjcmFwcHlrZXlfMkBkYXJ0aG1hbWEu
   32.12 +Y29vbD6IewQTAQIAJQUCXEblegUJAAAAAAIbAwYLAwcICQoGFQIICQoBBBYBAgAC
   32.13 +GQEACgkQMld2+8AnJi8WIgH/TQE605yPZac0fEvzuCTl+k/vOCP1P1FkfsbUm+rz
   32.14 +vMnrslso3UFLJIclO9rmQQINl307+fRLXbuZ1Oy34wgtA5xdBFxG5xASCisGAQQB
   32.15 +l1UBBQEBB0Cug/QGjM5TjeKyg6niEHNv+DQZLCdFd49RHzSk896aVAMBCAcAAP9u
   32.16 +ON2eSiUMGZZUPvY7W9qMQ5mt4MAYsZjuG6xw6Rdo4BDFiHYEGAEIACAWIQQYVESS
   32.17 +BVIHspNrshUyV3b7wCcmLwUCXEbnEAIbDAAKCRAyV3b7wCcmL0ZzAgCQqosUluGK
   32.18 +Yn0mLBLLD6Ryhh1YAkehYyzdchOAZdDgK2vqHG4BIFmPVvdTDYtbFeZ3mqqcjs7r
   32.19 +1UXZAJtYuPO+
   32.20 +=2i1A
   32.21 +-----END PGP PRIVATE KEY BLOCK-----
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/test/test_keys/priv/subkey_select_0-0x4929DC45_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    33.3 @@ -0,0 +1,32 @@
    33.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    33.5 +
    33.6 +lQOYBFxGBkEBCACxp7qY+FhxQmHicXiVNz65bZxnu8E72iGseEXctVJGv/F3J8DO
    33.7 +RU2mJ+VbKkx3levnCTQPx3Vwg77PSZyu8TJN/Nex9xSypTDo6fMtdOSWLgcKIyIZ
    33.8 ++fcsW61cSs7xgqdx/JaNzmfmXEe7OwoXi0I99BVX//uz1ZWK7nj/YiJs+xuTo5S0
    33.9 +lgWNQ+h0CrbSu4jT8ANMhCHCtqz+biFYATV70Rv3RNz0yVijYQ3h4tuwdONfo9gH
   33.10 +BAoESdhEdk12LJGrgvnY5FKOrx9Q0oHxdmM8Qg66pwd32pram0jeg0cQ3SK8VmBP
   33.11 +vfo24gtKsn4f0oy0jYuxWEgOK1BjNKgepF6FABEBAAEAB/sEgHxbR4HQPu8lkpwM
   33.12 +ZfW+M6+gtlKPfnfXe8XDccnXtqH7E8QQRhPRZ9XpUUFWT3OGq4ZI9xQ8CW6iqJoi
   33.13 +mcSdUtCxdxIsc8CxSkpqBroLLzfo8xp4X4v6sQkL225yks3E9vJmvgoGfaSoszaO
   33.14 +ga4oTUDkNb2uYTV0q5Xf3OAD9G82AXDWrjFuSo+f9/XZ/i1hTQFq83uL/KwB9zrg
   33.15 +V+sY6zvWKKsNngNLLGOjsA/2tE6HynVH2CTNHB36zVXdIGnof7EvTeFTCOj+z8k/
   33.16 +Npqr+05fr4HV7rb3q4Nney+sGyOLk/viE9zxss0nNeHPBflZiAjpUh0B82g9zXVh
   33.17 +LqO5BADEGHtLxqDczaIRVIfvZF4cGcDgJ7Qe1qd2j4CWhh1j57WkRXFDTxvgxL2T
   33.18 +E+HkSwmCLjjgzfLlxhzAQ37WmewIG3xPNCyl1HF4bzWpbJIl7NShk7W9L9FAPlq5
   33.19 +YIcF2gb/GO/nsVQSI4IJ4DqltNUpm6yBhKnbk03tCD9GIACiOQQA5+0gN1aKqjI0
   33.20 +D9g+P/FiuU2kwacBVr6NYgkncupuVD5P1pa8BYGY04UgwNBwZDi2rtRkSa8AUS0d
   33.21 +71wie/3aGeV8Ns1m/1MyH+4ERQAUARpAA4YllNIlCe6buic5nsZqSjf+Y6UyXyUa
   33.22 +Rtt9vRJF5PcjfGt+FiXJ5btFDH+Urq0D/RjpSIodnM51YVznd24pZfDDHOQRE/O7
   33.23 +zKGbykPghH3zv79ZBK7tWEas87UnGWgj7F5RPF+zg6AE6pPWp2z8DYFHJ1ru5f+3
   33.24 +C/BiyzTQgkZCLccFgh+xPgwpn0YlsmO86zTqGiRZidkV5UP3hpNpW46S9NplJP51
   33.25 +9EUM6itNccJLP5u0L1N1YmtleSBDaGVjayAwIDxzdWJrZXlfc2VsZWN0XzBAZGFy
   33.26 +dGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE
   33.27 +8NA8hCwHcMLCqf6vKh7ZgUkp3EUFAlxGCMQCGyEACgkQKh7ZgUkp3EVWRAf+MCTJ
   33.28 +Z/gIitYdJsGoYIEm4bs1JO+/lKZFSLoCtxtcIIFBDqsVhitDC0UtNyuD7TRXanNL
   33.29 +XirlOTN/uYKzP/IFiU+q0KoKihNWn7gK7tPdAQ5uwQZb/7omUZScnfPieurPuKAS
   33.30 +H4q5XGcqecET05FE/JORxEh57aD3/ILW1AakEeKgfC240Z8pEO5bTMda3BV6Va0H
   33.31 +GaHsq6GylvzKj2FmcxpbBbrUjxvat4oshTNReYHL2C3i4S4hALJCLO2/8pQzNqof
   33.32 +itRkn32oR7+PyYgXY2nnjPO7+Mr6J9Jgr237mzBeq/dAt4qlY5VI8tD1LfVh62tq
   33.33 +y96bbenIL8D8xOHWDQ==
   33.34 +=Aa/E
   33.35 +-----END PGP PRIVATE KEY BLOCK-----
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/test/test_keys/priv/subkey_select_1-0xF2BFF59E_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    34.3 @@ -0,0 +1,52 @@
    34.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    34.5 +
    34.6 +lQOYBFxGBkcBCACzk5CHhKqW0iOYWLo82kQEg+SC61mnxZcwOpad008YbQB/LXRl
    34.7 +4vlxssfZy8upfazux7lMNvz+OlwmGWt+PiVUqZmfWtOkMtKajtXfOj2hXyKOvcib
    34.8 +P42N/D9EGXgo723XAnx0TRRjf2AmP/w/yHkORGBNnLLek6i5J73pnK2x6FtzKITw
    34.9 +8akrX3nwGVhC3DYd1Hf/pdTpl3mp8Lo6bI10rpSMmvcp4/Ie5uJ16LxO04loLAi5
   34.10 +Ic6Q4+YX5WOOPHvdY09w059MXZocuomEmdY8PIvoef954k4+KZWmYpf0SKYOscQc
   34.11 +uznCWTMAQAdRNDjvX49IswRZVBvJYVPHUDGpABEBAAEAB/wNWlR9vIqCGCe9F809
   34.12 +YiN69yMM7cV8ZAUSeSt4RTKqnSGo00SboOLYe/6VU4Hrh/n4cBHMuNgGFWktt2fW
   34.13 +pXYEKMT7ZExmzL/77dFkaGxrF+u2E9GbYwCPxWkfk19BIqXsaMsVS3f6erRiaRFE
   34.14 +3Y921UnDQPrMnHaIJ2GH7KETyz83hbwugUhJ4+5ANQCBALr+iraVxMGkaBPCQobf
   34.15 +S5W7CPJOCL3q0avb1KVRTedIkR2CNN7ZcDWLUuNIoWUSdUoP7AQFYBkIMN6OZkch
   34.16 +yl5aYt8sn9+cy6aHeD1MkUGqRaiSeYkeg/A7HR3wz0MSrJVWZkj9arhmh2+jW6dX
   34.17 +k80JBADLgRu1s9iOuo34+VZs1+4CrEYTZ8VqqEYc4mIExYkgG3U9dDYOC+HyJjkB
   34.18 +uk7JJ68g2k7t4eSCWiWdq6FIAlnLHvng0yxYyNA1wIau4YkkHj9jNl0FiuItFysg
   34.19 +tagfF5SuEkt4QQWDproSaNzbOMlJqXBA4npx3pRi59Ilah8n5QQA4eZR/jLtF4Hf
   34.20 +BgNP6ipYzGd1hVbrbx+Uk/KBXgsAokcOUNGT68sN4WN6SrYOay7BicOcYbwacXmn
   34.21 +5fwSxxKw/ldAVA69tjNSnxGWt/z3R6w5/0zfJErQSlBknlieDqp/+Dld4txGoIXk
   34.22 +7DhhXbT92aOws7TeZGC4BrFRrmQrvnUEAM94M+i7KqREitHDfia6hmdeNAPSOkEd
   34.23 +zMskvPuaJFljgijCqUHKVbm4XmMzlC8fMB1aQWHjhuGK0RzWPimm1TNeJV88pWDg
   34.24 +yQS7E+046Q5fhEQ9FRKCXRnwNs4Eeuy9GjPkguyuvwUK8opaP4y5BbsFbU63tW+W
   34.25 +S624HciQ2Ct8OJ20L1N1YmtleSBDaGVjayAxIDxzdWJrZXlfc2VsZWN0XzFAZGFy
   34.26 +dGhtYW1hLmNvb2w+iQFNBBMBCAA4BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE
   34.27 +kYr26Ybzm2MFQeEN9ff6NfK/9Z4FAlxGCiECGy0ACgkQ9ff6NfK/9Z7IZgf4qLkK
   34.28 +YeeqOmVk9HARqcyhYYhBrGOF4VaLVW5lJES5IzK+kT9wc6V0qGrqTqHrlLRCATiV
   34.29 +Aths/Gyq+eUbHFT68WQ9+2BESyt9/dV36QQyQ0tdgYK0x6G0anzUYjpwac1zW4M/
   34.30 +v5mBDFqhTbfNO8FvRsU6Yctmgw07q3OFpZ6PBAOXlfalICzZ2RNzRCEOvKhZMuzf
   34.31 +UVH/GfXceXBDn5Db1jFkjh4RJCP0XUaAPV+pw3bO2Sn9Ype3h0dqKE0G5K1QVKbM
   34.32 +rH8LACR6WSXbGdjUyB+uXcqnUKBmaIS5p5oKOMU+xaATM24t651FhOik7uS4gBdv
   34.33 +REr6yp1ae05g04eTnQHYBFxGCi4BBADa2zESBybF1cT3QqoEoDMLyq0tJOjrEXPF
   34.34 +HmkB8TBWjQpQZD29jXPk+Q3EPVCn2xA3oHDheockOlIJX27a4l2rdDTq5wW7q8C3
   34.35 +Vu2KAXFmsoVA7tEJoSDwm/V3KG/JZEJis2+mz/OYK2KB0Fpy3zQX1fanKRwVfo1d
   34.36 +sazhFQjbWQARAQABAAP7BvlyPGFW9noD/18z/NbAGbGZSDWDaK5TMqZv8Txm7nMr
   34.37 +L3mqUAaYeWUIb8cGcXr1LtihkEXv1ZM4Nw1AAqCxHG0LvdsI1NONM2LKBfe7ImHP
   34.38 +3GtVJN8ErwoO1pGIMjM2MG8RpqUSvP4aDk5w1/qHs4pdPJyQGQCg8/QfsjI9xnMC
   34.39 +AOMp2IxOFrIQlEZNuIDMZqpgo2s0lEAMxn7nQLmOhnBjGWH5avLi6md8ACefvhre
   34.40 +IQ11pj92lx0vtIi9Hl2C2psCAPajYmyHfTa6QdUvoTzY9V/Q/Xem+Z5r3E80QcmN
   34.41 +wkJVnZ5t31o6xouSH8hV5bCzmnm3AFMJQzWsSH/TGZHVtxsB/ibXietdyWTX2kPy
   34.42 +Qpj4FvRAcvONHTbJp8EXVIQkLRKUNZR7E3zxLySpRD4sKEBohCgkzWWuupM06JC6
   34.43 +cZ64UcecTYkB6wQYAQgAIBYhBJGK9umG85tjBUHhDfX3+jXyv/WeBQJcRgouAhsC
   34.44 +AL8JEPX3+jXyv/WetCAEGQEIAB0WIQTZpr5HRPjJJV6vGvKUbbiK2DrcuAUCXEYK
   34.45 +LgAKCRCUbbiK2DrcuN00BADQB1V+lYhcbX5XNZUcnvaPyXJCCmgbrtRM+SzUtkJe
   34.46 +IBgtsCfyo6Z3fSq3vl7s9YB9S8hKUBTzzeTi36i2fwlfcGMFgvB7N0qHJY3mRlzo
   34.47 +JXG2HpM55WELIp+HmJx8WKk4kYQWzFxarclm0u7hrSa01vwHcLu+751Lkslqe/83
   34.48 +D8IACACf499BLxGvC3W537gED9GIOousA5rB4BCdFvaXdfpXu8EYFI+cW4QSgtF3
   34.49 +lSp/7g5ggKkRyUtxmAcNBdw4V/1wpzwPvk6+0RKgo2IRY+r6fpiML5b4ULuzT38E
   34.50 +X2CwzwNerYuAvJM/u7BkzzmP9W0ZxkFw2xBTEvLFMvXyXEGNMllenY/aP/zX41lf
   34.51 +X7o3Y6Zq1/VIbYTwIxb6FyWWzNb5xpe5er8umQ7Dxu2pL+0xmshiFjIPymxaLLEk
   34.52 +9kCOqrl8q9OHfxswJvZu0bDikNOV9oIjjJFkDxQGirE/+zQFHxca0nnqwlkghb5m
   34.53 +kTdnvrwnWuCV33IV6KVBaQNojRlZ
   34.54 +=DSim
   34.55 +-----END PGP PRIVATE KEY BLOCK-----
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/test/test_keys/priv/subkey_select_2-0xBAD7800C_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    35.3 @@ -0,0 +1,43 @@
    35.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    35.5 +
    35.6 +lQOYBFxGBkwBCACQa3Qt8LaXvGZ1WL7qJyjeKNd2xW5y6DO8+6Sm6AxEdRSkEg0w
    35.7 +DuceemwhCl8p/VlLsUsqnBXqxR6j4cKGQkSsmvZhZt6EFcPD9/OU1CovcbzylJd1
    35.8 +C8bxFypd2qVpOh0i0lOfhbrtbzCocoDVWZ4rfiMPUWy6E0HGfEcxU8GPMOSIsdbC
    35.9 +vnbZbZrgW8VK8f+vjn4FFrBtMF3Xs1LGwAuzSdTYW68Be7k3MkKKkJl0QrTEzIxo
   35.10 +IEO1EZStmo8VM8nGh0rLe+mQI9TaN/Jn3DCE4m4gmS37hyl4+MPkM7jEc1eJ8DAa
   35.11 +EYpnDoTAs58OBpuHBzsXXvFL/hA5U4rMl9mbABEBAAEAB/wMzGD9iJVTNBXWX2N9
   35.12 +Ml7g9TicT28ezWzMWiFOI0ahsx3S/ms0b5WpcfWZe1GnUcrd4Nva7lMo54gew4KE
   35.13 +Iw+dRkGrAb1FclJTexVB2AgsWoWBRTbONMQlbcVKOkv/W8WPkO5qjCTefBnmoPhs
   35.14 +L9F1uZYXekKgPir4O9+T7lVlwDA5bApDqwHRHqaDjOgUY6vb7ciBYNZj8AfPDbwo
   35.15 +hXeJZWs2BJrcIpxGyo8p9sv9QPdeXCnmUy/u6ABv/T56njx/p5nw5g7beDJazZJh
   35.16 +65SOXqPMNpMVbABL9Sw5YHTorGuCob5rKa7W0wgzFgIOaNKJPXuHKaMwNvfwJdi6
   35.17 +MohRBADAMbPK79TOwrCNASFZBHGWharfV1ncniLg2UrxXyLZs+taNfbYo0TorBV3
   35.18 +PvNx3B6V+t9RCOC0yFmBOA14gQbHo7P8V6nn/fDVPbhDQklFpiyZ/+dMvvin9mzV
   35.19 +Jdcv9VKgz0CbMPgRZQp221fwLPIOiAf0B5YFlpF7eo89hOiiqwQAwF15lRbry4l2
   35.20 +GMXE47b+SapKZDseYC+2d3VOqoT+fu1/SmpVk7I6llPYbFPSULW6HRlzNiJz9qbX
   35.21 +zByBN8Lf7p8Xu+RJUoq5vTySnXE6kDe0CTvll75KVDqCWEmCTeokBNda4gAcffG/
   35.22 +zh+8+PqIluz34fRAJut6uTUkONNhJNEEAJ8rO2MYmWpCecpo2jnp2KqQqiaBQX5T
   35.23 +p9n9CL/5vcza6POGqpI00BQ3P6jhrkgcu4IzGL9g9cNt/D34SIzWEGdcI/RDEwR9
   35.24 +6+xS5JBbcOwtGaSW7oBa5EyQ6mPTLwpqexfWzBRSU0oeyPUJcFs8qVv1TRSj/r0D
   35.25 +FC/TBswOMV5MRd20L1N1YmtleSBDaGVjayAyIDxzdWJrZXlfc2VsZWN0XzJAZGFy
   35.26 +dGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE
   35.27 +iJQgLj15HJVWAFi9d2drrLrXgAwFAlxGDH0CGy0ACgkQd2drrLrXgAwt4Qf/VbzQ
   35.28 +FNxLHFqi6x2mffvPR3gUtygMyv3EjlH8VOyDuDmGu3nCm7Q4LdtjtVhDRYlmwaQH
   35.29 +lVp2JxRWDVPUpru7fKxMxk7H39oGoh85VItJAyqZZhCbal2FM/W3j/+pnig0Q2kN
   35.30 +oCVlD3WZg13Ejw/cw7z4zasaT+O2AJ9KzRNw4Hk5FEnlhjuSCLdox/oMCe5RM5Nm
   35.31 +UazC5m4ejpqE/hryLzp10PjCMJCXz2fMrAWMZbVWB5vmioP6oR0UjiJdfnEPjjJ7
   35.32 +L2w7A08j6kATh4+hPG2FXbox6J3tBJ1flwWcZGiTUYEzxPpq3ArOqUEypddkNdrs
   35.33 +hMQnwSjBJzdFlR4beZxYBFxGDDEWCSsGAQQB2kcPAQEHQIxutjFIiJAtLbBcHCnX
   35.34 +U2jM8JJ8Gz8aGeq2p9KnzVCrAAD/Q84qakEUlqTydLlNFaKwPxSQMa8yU/K0H15X
   35.35 +UqiaO6gPP4kBrQQYAQgAIBYhBIiUIC49eRyVVgBYvXdna6y614AMBQJcRgwxAhsC
   35.36 +AIEJEHdna6y614AMdiAEGRYIAB0WIQRWH8vG5CqfqndZdeTDVOVYIRxyngUCXEYM
   35.37 +MQAKCRDDVOVYIRxynmFFAP4vQjE4j3g1965DVPhMMpmfJ1lhOmqTZBjB7ivDWIDP
   35.38 +OQD/fSq5SYLRJYFnHT27WEFut0DlwDu8/IHxsex/F00oQwLcPAf9HYxMGJGihaDo
   35.39 +PzEUZXCTBhjCoVJpah7JPe5NK80DtRn+HmuQyoFuxUHLKVQb5QkWm8diZQk0/Lf2
   35.40 +Dad9QZttDycK5EKfbVWE6TlS8bCbJkGuhtP8qcJePT5Glo1xQrJ64Cb8Moh3Xkih
   35.41 +WggZdqO7EKEFxrpDxbDXLjoq2emdHM3VfjtMwqLm+TFbU1gN9womWSucTqG52+Pz
   35.42 +4odazRDC7vsH6+rPl4xyn/gjBBJm8HFxvw1ehoTNFqxUOIgicfnDVsJzcn30cC0K
   35.43 +YPRFKal5dBMuhdCeogKbj6/HOsr5IiPnTXl3g7sHFIHmHPsYDs/CKGwqkToeEFkz
   35.44 +TmswobwksQ==
   35.45 +=c+dd
   35.46 +-----END PGP PRIVATE KEY BLOCK-----
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/test/test_keys/priv/subkey_select_3-0x34F44C02_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    36.3 @@ -0,0 +1,68 @@
    36.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    36.5 +
    36.6 +lQOYBFxGBk8BCACikTVRrTEv3Ak3GBm6qNvODY2/P6gksIGgFCqWf6igu2xcBFq/
    36.7 +lNSVXTWUBSHKJUTXujizohDj+uu8ptRxiB9pIjCED10rP0pFhknYRXVInfx6uxGE
    36.8 +ToZ30VymvyVFw1RiHd4Fxg7fg3ri4+8rli+DxcgpiXySusibasnWjrUJMBDXMFl9
    36.9 +LpKCXaS7HNuNQqNYImbM2x3X3q66XOgPb7VIzj8nqdCugASTrCOMZvVytGghPATl
   36.10 +03JzFDPmzbVyxQaGPCqOe9eLVsy+YEvQaZ86qPUiJuEJ/7+ScwvB++kjWi/J6qTR
   36.11 +4SeghWPJr63DYwy6Xo6cx8Bkvhriy+JnYIrvABEBAAEAB/wPviUeMDnrqxC/Y5eW
   36.12 +QmTqytg3tYfoaalb4agQI/OmARBoxsks9VIy1rBqEacohrxocbGs/5xIH5P1lGhN
   36.13 +SEPWcAenuj8pAXuFSRBcn7lQW3BISFZVbC9MahthUHBhFZ3V1JOcFoZ5MafUUgNm
   36.14 +wqf+SEhucVB9exYTKt+55d71MSljQ/e4Dn6XQQq88871uD69D/EVU/Dw90oUrUnz
   36.15 +Ty3U3RVHw2GtK9DUHF/SfK8Nc69u3IMpjpRmdd/zIGtnrT/mhucCFkwnfSjn7tEx
   36.16 +U4XGgNCbsVMDDStTn669SMD/VuBJ/O5ct3PR6BTc/gpTKQuTAjY+sUaneRbvKpOT
   36.17 +vqvRBADHzgpWllmvCbZc9x7vIJwfUsGQlSS4QbJHtL8UYke58oS/LY7LY5IyFIDS
   36.18 +hhCI9oVYbMFmWRd8dO5I8M4PjTogcv7BwP2zoS7hb18hwjUZ0BNoCVnZwrjZ1HQp
   36.19 +d+QpdQNeGmZG7JtKGM8UTAWV91MlfP1SST5gXm2ZvXcXs811XwQA0EoOjk5ZMEiQ
   36.20 +7xB4JhXWJ9aPR3k9QN0ENFwazngMCufOljBVFqfdv3XnVLN27xdpdD5ajOEW9p3K
   36.21 +qJYFhAzDpmlyy1OkVHLtO5iXO9ahyl8qRRg9KFb7IQF/40duR+VdOj6+3JvjCaoq
   36.22 +AcIUh680wxNGw6Qree5npD/Aa/oNxHED/RT71bza2n+YKaTZG7ZDzkEtG6+aEooN
   36.23 +zWpTiD2bF7/hnS2Y5YAwaE2NrreI3dL0x+aq9PQEZBKWna7vhvDaBiGSeclafOc0
   36.24 +dSxowA9BDoiSV7DFAuh3hEOsVQyjjGUcagv8FxkYX5VCEq4lJf5qhHMuDeqMhZXu
   36.25 +HsfFsURIqoocNmC0L1N1YmtleSBDaGVjayAzIDxzdWJrZXlfc2VsZWN0XzNAZGFy
   36.26 +dGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE
   36.27 +XqX39xuzm095JNHo0RxnYTT0TAIFAlxGDVwCGyEACgkQ0RxnYTT0TAJHfgf/S01s
   36.28 +cxkskxHWeXwUfVeb/iYbX86TtIB+AJfsiw5HavSQVdH2gU9m6ZSm/yxM9+WRU4uA
   36.29 +RaiXRd2HXCMwqx3IIkPjNlNSyB2xyTLdsddCr0+Tfw09ELbgqn9xZk2d4+EB52QO
   36.30 +2D7sYfjV6Rd/HBtEfvihr0DZtXQA76TTl3dMUVPP/lq/FmaGFaFEROtnAKkOnLhv
   36.31 +cNAQVFuVmZ0cZRR21r4qeoblOvSHAWqMSSQ6H0f/xkPJj7qOqGoBRSjyPdLBogQe
   36.32 +YaIQTDChtya2WCEqKTF1qPsGyUCLYJW4ieFLXirfQqFkuGgh3sflWSwF3CYH3/m6
   36.33 +w3j7aAuVXTVQjb3qk5xYBFxGDV4WCSsGAQQB2kcPAQEHQK1WjaIbAxPLWtVDwrGs
   36.34 +BTXx5xmsPko0/7acLzBEPGu5AAD/Q3AYePqEt3mQkSZvZIJx8uirnQ1i3dn+Xv+V
   36.35 +7agDZiYSWIkBrQQYAQgAIBYhBF6l9/cbs5tPeSTR6NEcZ2E09EwCBQJcRg1eAhsC
   36.36 +AIEJENEcZ2E09EwCdiAEGRYIAB0WIQSoApShnz2Mo/d2YoNaLJmUAdrVJAUCXEYN
   36.37 +XgAKCRBaLJmUAdrVJMKkAQCGLN1t0q/2PpPH2pSGjxV7Fx+JVTVnOzJJqOgbligZ
   36.38 +vgEA9yg+XIe32fvppxa5Hj9iVyrAbxHSt/SMa5aAuoSnAgm1SwgAidW5rtpCgmdK
   36.39 +D3uEh0gp3aLnpJqx5WeTkw57bIgzHouztF9avCP/Adg8jwjUUt7SsHoRNN6D8w8Q
   36.40 +AcVelf3FbqHtCFrUnMteWABdbLXoOHg1c8l+mnIfDt14QoOQszBYhOAdGCt7fyh2
   36.41 +Q2sZCwSIxsIlVK7d/pjZ2UVBGfwArxVHHLwcBhJA/g0M6Bee0Ak6gixdRcV56+cN
   36.42 +b/S+sbMXC1RPR21D0pTikEvydRhnFozcLmOSAUj2wc6d0UAvmVmP1G8fhgyjSZ1H
   36.43 +I0tnqhLgubYwLKinnpjkdF0yFqq0Er0hNLPIbM41UENj5BQyucmsfMV9GkewPnWY
   36.44 +4+MP5+KtMpxdBFxGDZMSCisGAQQBl1UBBQEBB0Dr6TTal9yPtgRTA6lJpNCca1lI
   36.45 +ZUrlY7rXd6QGU1xxDgMBCAcAAP96xpYMKeDFyT7TXf+yaW30evDn/T7XvZnvL+Tv
   36.46 +/XeaIBU5iQE2BBgBCAAgFiEEXqX39xuzm095JNHo0RxnYTT0TAIFAlxGDZMCGwwA
   36.47 +CgkQ0RxnYTT0TALBwQf/RJttjrzJWxAmbTtNTYUrs3ze+XLN0u/XN4Hrl0Wr/g/a
   36.48 +0+aV8c76ju3jHLRK9NqidediKiuzJL8d1KzgapNBjBp67RhPrusRIplo6YAggSYg
   36.49 +5ZuPL6zqLe9ZZ0evhdltUeCRNHegwLDVVLp8xw0T3jQPdSuVGqI88iu2/go1f1i/
   36.50 +CyjzwzDNVnYzCYozZsrF1+CRyBsAsak85F6xWgIr4A7JqZ1UUIAAcZlPUU27szFA
   36.51 +w3QL/dBpxfejlXK+AYOsM3/1eXergfWxyJo6J0CAIXA+9tCbOuXbIbJReEdfdQwD
   36.52 +6vke1icWTwrXsh4Zt3Zag1sXq1Pe69pYUVSvglHYlJ0B2ARcRg2qAQQA1LNWmbgS
   36.53 +HrqI3T8vYGg/18Cf5B9klY4UWuAj3VsdBJVxp0ZJwzmk/N+0b2XTuWd8iPlHuGn4
   36.54 +Plqk/zf+C9YuWOtXUCuRGlQeBuTs5LVgV2QeFf/Q7+mZHOmxOPO2gTlPI7S3TcQR
   36.55 +aB0nLYSUK/11EHHMtauy3LZtmdqzazKdJm8AEQEAAQAD+gIsTKfBY6w5ld6ZPDbl
   36.56 +7xgno94aVOSE7Yb57lzClVH6cjfrgJT5zDwqCHr/UcVS7DqSBPceBu4hfLkqWCs2
   36.57 +WE0T8AqmJcj5RyaaF/36/sdKZ7YrCrTrkja0zmrn07pSfI9pte35J2IzXidQtUmX
   36.58 +Q2G7m3HZjjwOHWN++PoTTEyBAgDjGo4004LnfpcLt93Uob2e9uZKjIbzcFiqxkGa
   36.59 +sHVv4l00SyukB0lUuYtfeT693sP1XLbAYiN+piUxFau4dWFhAgDvw6DBTS2+/ctO
   36.60 +D95lmEHNsPNZgp535G75wFbBSeBJo8lJckljv22DYtYnbHbEL4jxaLn4SGA1898S
   36.61 +HMuFpwnPAgDkGGuUc7zYqME0xxw04GAvdPJ0MW2Mm0gLwqeM75GSI3oOBUcKSFrd
   36.62 +TSYLjXlMPTLXYOrxxEFkVaWRPleUPrj0pHqJATYEGAEIACAWIQRepff3G7ObT3kk
   36.63 +0ejRHGdhNPRMAgUCXEYNqgIbDAAKCRDRHGdhNPRMAoZiB/4rSiCXB5PJMAQhC2B3
   36.64 +A5pYQL52kP95+ru4VjAUINmpWb/puycnQInTu3afKsFHRV/pBMBRbk1yI3u7NGt+
   36.65 +x3REr14KL/k5e2q+MthQPr0Hj13jAToZsc9+9hZzlDl2fuje8qx09hLwZ0qqmkAm
   36.66 +7LzSliMLeot/qr19dioKSsdJWJdOSpsHtEUt0tO0wbcBXlfE5NRN17bH9KgOb1L1
   36.67 +15BvklWlglP1AplIvWIc63ii76MCohW6Sth/QiLOmVBqS6trkQxyYa0GOGnkSBkC
   36.68 +8Tn82MMP8AMlGgpdFykb+8xYNvHCcCJrJPI3ABCamGe2DBH/aIbzTcMXc666+8yP
   36.69 ++rtx
   36.70 +=IIBT
   36.71 +-----END PGP PRIVATE KEY BLOCK-----
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/test/test_keys/priv/subkey_select_4-0x6E6C7B8A_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    37.3 @@ -0,0 +1,49 @@
    37.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    37.5 +
    37.6 +lQOYBFxGBlIBCADQ0BAuaVLY6qVfirbMzGVE9o7T9vJcRuLU5UaQe2xVS/qswu6T
    37.7 +q078R4ItAOItaSUhP081MMZNHCZmMHtJvnkgGCQfGdUnUntbx/McetnNHanXOFtX
    37.8 +51H6rBT2t+0kFQ1FcofG3jXlOgEi3ISqv2MBfkhFG+feVmc1uCcxp4A2pFp+cLhv
    37.9 +nWIJ7ksvKyGM+tbQOIpY+ylYcFWDqCzSZ2nv97U0GMVY4cuKEZpGB8ArPec8X7EM
   37.10 +WSbM6rCHsWSdIO4XrwYazQZeBnIUAN44h76SkSdNuSqJgasXNmJFaMoZtZ8JrcCQ
   37.11 +Zrre+z6CBDr+Zsn5PoqK16TcYZKxRv1Q5MczABEBAAEAB/9lMJ7WzuV+Bt/TF/aT
   37.12 +8m0U6WK3p1E1lIhx4RW8CIOsJiC5PdG9r+Ob789OncH9fZmnrfVlclh2n7CgDtiA
   37.13 +GRS7j9dZVvxrjNYI2TGf2IzZkIlwqXfidk/M6T1TfjgmJymCQQk5Pw/hIKXSTgjg
   37.14 +cdS5sYe2LdrEbRyg9LfRoTlJwKTpdBZQcBbHUIuYWij0HMabOPW2ZgJKTgGdzLuo
   37.15 +UdIHTlCraovpSX+LF+AMQmMbQXVuSnO8bvSSENe24xHeOv7hA6QtH9E2puQQTqR9
   37.16 +cAPVrcNa1rBg8pWi9EeqwocSMz/Pj3dKj4sF53xK/JSrmzL6ArNguZUQwJziQZ2/
   37.17 +M6c5BADVfcJ2dDMBNoWacStxETAJMK0msIg5JD3fGckaEFAnuuM3U5GDrQfD+Ipo
   37.18 +WpUsEJwohEvjU9vihiFHz0nO9x5jB1oKoHM3Kq34xBlh4B9jJC+pbJptVGi10nPB
   37.19 +pzbO9f0A6xbTJljVxv5HUESoFwaICbwm+CWR/CSqMglUJD+rbwQA+mPT0H/NJPKX
   37.20 +3MVFgj7COpiPMciUyaeyVIclIh0HJHhqmryPSliQrbHjctsOgHy1vwLhtMHwX6Jm
   37.21 +w48Brt411SZRP6pUBOGPkjO100mYlxlX9rRbziVY3/GVHqWTyG6Lzt9HTg/bNmgR
   37.22 +MkaHpLNJ7LliYHM6F4AFFSmXgWVyDn0D/0zjTLGWQL22TmtzlqDPq8twgzrKqyVR
   37.23 +Y5LBz8U8stfcBy/8GUWy3bWgp6mUTOywzolR2CXK4qf0Lkie9Ooi7veo2hRNyogq
   37.24 +QHsy8IGtD2KgwDFrGRHD6K3eES/kbiqQvGPKc8z8JkChYFk9nzANbkj/UILz/6YL
   37.25 +Oqh4mCfqAJnPQke0L1N1YmtleSBDaGVjayA0IDxzdWJrZXlfc2VsZWN0XzRAZGFy
   37.26 +dGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE
   37.27 +Hg0nhkTi4pOp6VPZrJf2f25se4oFAlxG8bsCGy0ACgkQrJf2f25se4rBFgf9GFyV
   37.28 +dylvzmkeHcf2AyL/+9xXtwhIowp45RWBwyYum4kpbeHa7pBBBCYthDRFpIE+G22M
   37.29 +Cf1cPEjoGqvRbBO2AusozVeqQ2kQ4+Cb2aC8I2Em5+7aFgUSN0VLEKi/9n8eMu0z
   37.30 +WBVZo+QCGOXAZ03tlvatBd+awNniXQii3G49roOdGzdv5v4hA/hyCl3IqIaJIpRK
   37.31 +z1gEh8EpkapJveTYCVH7azZZubunX1O7cOuDxs5IOZWQBijiXA6jXsqMI06VJjX/
   37.32 +UVeUViQbywmlTjnRwImAyZsWPDByCPR362Ar+Y4k1iwgw9TDnqmnWiCBT6NwaWFl
   37.33 +VjmCWavVGuU/tUWjm5xYBFxG8cAWCSsGAQQB2kcPAQEHQPT1C2N0d7S7xVo9hp05
   37.34 +oHdabF9O7OFbOFzljC3GdIwdAAEA6IiGfhtMFvL94/W+dVe2k55WJ7PAWq+exSR3
   37.35 +/7oEgboSGYkBNgQoAQgAIBYhBB4NJ4ZE4uKTqelT2ayX9n9ubHuKBQJcRvHzAh0D
   37.36 +AAoJEKyX9n9ubHuKvy8IAKFdb4EAiNZ2Knpu7veEJUtHFU5RqK2n36Yt5uOWyYlm
   37.37 +lMvIvfdnnWyLZo8n9V7ZviWbzIOQyljQC+8AGEWzmfe8588cFiSmAO3Z+vgL3Gtp
   37.38 +9y7DOerGQK1l8VZDTthv9k00QiWlSYRNSiaX51eNuCX6e0/tm2zM/eSZT3lmgFgf
   37.39 +qFm57S3cVcrb0hOp0gVEV7KyOWTd6fVwHOoH0SQJMEhv5QiWe+1bN4sj35mSD/bm
   37.40 +FFhJzGBytC5XxmaFy5y5Ej/M36gTOd29R47yHp9+CcxrPJlBv/ulRT96aitx8+PX
   37.41 +plQiPjA1gqf2wLaijrG3Z7CKTw7P9X13r3TYAMu/slGJAa0EGAEIACAWIQQeDSeG
   37.42 +ROLik6npU9msl/Z/bmx7igUCXEbxwAIbAgCBCRCsl/Z/bmx7inYgBBkWCAAdFiEE
   37.43 +9tfb6mpSSdbhzcPaegO9+IiTmF8FAlxG8cAACgkQegO9+IiTmF/5ywD/ZNFuYrMq
   37.44 +2h4LE7XffiBwbvUbdQ17ybLHfkM8gDQvJKsA+wZjliNP9bpN6hZG6YyDvPOSQq6l
   37.45 +YoPbd1gou4NRyTMAVGQH/jzh+PV96UJCvCKJWaEr9yGWPWkgSa2Ebw1mNzB2maW+
   37.46 +NT83Ywckd61747dghmz5ETuXfFKXGp3nW2f7ozDs2Y8P1Yh6xMge1JN66ZDPd68J
   37.47 +Z2OawG5i0r1/9hXWKrcJQQALkzYTFij1IjZQEMiQ/1sgAAybLHPVOeXv7o1F5EZ6
   37.48 +sCQybQ7RCTFLRkEFjc2OjIeH3+NMMdibEPSEtxBz5Q+kW/dB9c4EGNplVuDSC89V
   37.49 +iCC+NDSi4h97dPu3ZWY6SL2+4K5lOEoVD5XB7rBDHaT4h8BvGe7l9Box0W/y4pXj
   37.50 +8NePc/YZfuEATtasqfObSTShXTQf2HIJgGwuxXXAQp0=
   37.51 +=mMuL
   37.52 +-----END PGP PRIVATE KEY BLOCK-----
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/test/test_keys/priv/subkey_select_5-0xD106E693_priv.asc	Wed Jan 23 11:59:43 2019 +0100
    38.3 @@ -0,0 +1,73 @@
    38.4 +-----BEGIN PGP PRIVATE KEY BLOCK-----
    38.5 +
    38.6 +lQOYBFxGBlQBCAC4ZU2FVdlU3ghrsETX/G34YFP7ywiy5cHlayODWygJBOz6w1MI
    38.7 +OiG6tlGzoB7uGMRfByIz00Ry0GoJtm/shyrh2f+qrT5Pqw38SpjJ5PipMndNPaQh
    38.8 +svxWnrpiSpnn/948uqoUHVD/oDjcJQHLVRb1j3fW6oJqV7Z2IjMvhunCtmJ+63fO
    38.9 +M9dsV43oYRcMv13y3rGKsK6OLBuOVNXVbpRKN3Q2oUui2qiVsq4++ABbBQQN9Nft
   38.10 +8poMArL9wLCL2pUB+ZqMhx9SW7bYByyQSdiwZj5CkR6EwNrm73ZIPgByKg5193de
   38.11 +s32DyadnQYbbFQu+YjMgBYekfY8o8LtZEXpfABEBAAEAB/9EkEJlaDkB8fc+l5HZ
   38.12 +n76CQssnjmSjJIRW2mIflxcJV4AIc/VdU0Q0aVNyz4CAtsvZq8zfaViDupQbHW97
   38.13 +ivz6crU6kOVg+TEflNtAAvgk7aNnoJp1f1iNmsKiBqw4lC7d9OiFxyrVig1qagZD
   38.14 +RVXeo+SDELrCcO/i+C+BJhCoeceZtpA69vmfou3bYT4Fj3yc2rAvJSLpwJgdRp7d
   38.15 +9tzbT9oOoca614TY2dxL96xwWhKuOSTj9XaG9UnvTa+x2wdtEBnUqodjEo+Qlwka
   38.16 ++QzaJSZoqEfFDBMWz7bdaO+1/csCPMXXHyuDDib1/7GnAU8kouDgrHdDAqQgLa++
   38.17 +Pbs5BADJlxxygBtqYleSuGorV99+RAoDHl9AIqmj88vcXyS8T3GEjZ6j6jWIUsTA
   38.18 +VBV25hCFM6YaOw9zd7m+Mxcz7KUkr+c6u+fmnn7p//0eLDM590bBFI+qlxTreg5q
   38.19 +GP5RodvCUO586SCDwL6EB2U/jviH9zkRET9kB7OpVGKZCbFUhwQA6ioh8K7Hhe+D
   38.20 +7by8QoJap0VSfkH9FUh5Yv+toaWWIVjjeS+kxSlL9Fmylpft+m/BOUcibvXBaFlR
   38.21 +/0kZHekMcaCm0PMc0AVTsB2Kro5BWOBMKEBIdEGBjiA1LudLWmIBNYVjJ9VDG3CR
   38.22 +xP93g8OcPiDCvgpz4f2uQGDAVFkOeWkD/14CsWLPDTQlnQu1NMVMIn4lu5btbuqW
   38.23 +Bt1y3L5xUQa7AQzFRq0wAGCnmwAEXkY2TUaXK/iLYnu+sugBaWb7zzd7kZ7REWsf
   38.24 +gUwihJljDOwYmUrGBf8FEYiw2xTJCKbbBUrCkkjnUt1HNz3chSkNuMcVbuQD73Pj
   38.25 +ZNm/BEmwFqjnOzW0L1N1YmtleSBDaGVjayA1IDxzdWJrZXlfc2VsZWN0XzVAZGFy
   38.26 +dGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE
   38.27 +osALEmYMy1dZ5r8YVDFdKdEG5pMFAlxG8xgCGyMACgkQVDFdKdEG5pOa/ggApoZj
   38.28 +V/dIerseQjhRvcmsb8AuCtYIeGJdQsI2vmPvi2v3sblnHzJN6fqHX1kjW+Anm/47
   38.29 +O8Y38iCa/ClGbEzPlNIjt2gbRU2fDMFXs/Y/uahmJ5im8u1o/5/u99t+Pg8xWngy
   38.30 +xSMfbiCUah9+sWV926qXMgAWLQi+WXEth9hJHDr0ojnSYZdv7hDj1ja5Ureq+f8c
   38.31 +vZN1JlTT5Eek3mUKcCFGT0MgBvCw6oyXuMS2PhQETx0MLI/A4DZ61I6V3CugmwwI
   38.32 +UV8R/fzU/n8lF9X+5To+kyiRhznB/jaqXmG1bpF+lpxTegbBNcfEAKHhHcj7yuEj
   38.33 +zSKSvGu+duxJD+tXHp0DmARcRvMfAQgA4nTlPF0e8YPjg8iwsdwjFsBYUPu4Jga2
   38.34 +ZKdgMs54LujAs8Hy95JKS5i7Dj58EDzu2WLXkBXQkm9iYCd9K5dPAdXb56aAqtrb
   38.35 ++FXGqvdIAeeVIN/G7m3r3YcqZuypU7K/TsCU1/l+AWOYi0i7P5b9awVY9gAVTkB9
   38.36 +fglKMR7FlISKt4vriwYu3O36BWNx7b2GpsJmMQVoA0EG9JytnaIorNBjvFu3siJ8
   38.37 +PU0SDIhXJUfFVPiGiw0xmikxUB87tBnAhtqsHh56KG2zKnfW1thG5YHzPiLkba+u
   38.38 +zlXUrbBUxzlY9PXy1dBGR/Uli1xQD9YMtpyyD7P4r5sHLk5lc/aCTQARAQABAAf+
   38.39 +Jw8Z/d4i6O3CZ3fNUDQjwjgVU4yDL93fBj/fRgwaKx8eo7KbbWuoUF8svlF1NRjJ
   38.40 +aqnTe+jjU2qOSX7uJj9gE3U3S36KuU1r/OqQjGr/2sI+lM+8IGJJuSkn3V5K+2J8
   38.41 +gEETuyevfd5XkIiQMXDhz1x6Al4zzo4thvhjuVKxKgMaV6SEqDcOoUEd2lh1T/7j
   38.42 ++656x3G1vcMRp4dRtVSmKsVeBEd3wUxFLNZyvJxBMeUU32+o3MwuBnTiTztLjBil
   38.43 +77qWc8GZMlST1nTX1YcjL5PPLy1rBKmHp+3iqaO9QeE0s4McAAlUY7ep0E4H1TAS
   38.44 +soicTRg7g3n5vu8yVFF++QQA7T/DxY27CSn5itx0CsJdHnSj8xqgFmIWP2u6ukYW
   38.45 +BYWbYt1lPNfFn9Mc4dC4jBYcBEagD1WZiz16msGqdcwlzxLTtbPiWyXvd1KG65hY
   38.46 +QgLOCi6PO+fNrNZBmYFbVoJxIr9+pjtfFOHNMFQY02prm+3ZahX0R5Txp0Jn+uZ/
   38.47 +3eUEAPRaxKAnwKJH3e0NPeJCQ0b/sJaQ+Bp9U4kFJ6dbUkjirOXK7+8c4J+3qu4B
   38.48 +e89WEtGpbC3X+sGzMPZ/1byvddeMJWWA90qOedBQKRPpDtQU0NkIUOUnXmKpsKBC
   38.49 +UbNMLtSq3OOp2hSHPKyAaZUQ/iqKgnT0SMvitLdKlZOBG4xJBAC1pDtxf/HHzG/J
   38.50 +gBjFJnfkDXkRabciQwYT+wqHOjpDSysiJZJ8rQHZBvK4WAkxJq3F1GxSRdTU2xpb
   38.51 +8WQ5dMqNN/UXEhzUNAKlVcv8LZxElXcDdAgsK/aWG6DNONIACHi/k9uUCmFi4wbO
   38.52 +/pWPsCOUqJJbcdGZE/CX5RLypkLmUD2ZiQE2BCgBCAAgFiEEosALEmYMy1dZ5r8Y
   38.53 +VDFdKdEG5pMFAlxG81ACHQEACgkQVDFdKdEG5pN1WQf/cYE9+f7Q5aNEK3CtxCIj
   38.54 +Z3mqeHioItNVW88E5OLbpwfoPCWBVVTTHmOibeHdjjo0P/qZrOMTzkgLfOIiLiyS
   38.55 +6D/EHReyuX2GjXuTFelcccytcOuPOPmJl7yvAVp1wfOwmIX7gvGjXIeqji2Kfv3l
   38.56 +Ff35g8v4QQYGsSVG5fczysSsieMJBTpCvYc8Y2MYdk1Uo0h180a448yIaCRnGdM4
   38.57 +STXdj/g9HSwoyGJFCDQx5zes99jRSlmLJAzNALkE+oY0r0QdMHPTVCKVHBrRztZU
   38.58 +UkYRAoQ7hHbErGj8spqtxwBMi8BBDOYrD8dCltGPOH1Lt1HDH3E+Ju4VJwfZH6gb
   38.59 +rYkBNgQYAQgAIBYhBKLACxJmDMtXWea/GFQxXSnRBuaTBQJcRvMfAhsMAAoJEFQx
   38.60 +XSnRBuaTDi0H/jJJ6o2Jf8kX/l5BT8FKvAA+PpWO8BFQEFPMsIJKb/n2PqAc8c+U
   38.61 +Tizkm+bL4Dgk8m2lMmluzR55KJr3Arau2BTrHciXNEctVIEeobUC/yIRB0sMX7hK
   38.62 +fU0cDSBtOJoZA5JcSIFoUY4A/I1Suw3FX2uZASepsWPcu8Rj9moNU2lyXoxyb6xv
   38.63 +zEr9DLj6Rc7211VvUnPeXhYRVs/PlMWp06pEzDr63f3CwxxWXvfCOEszIw51OHYr
   38.64 +DdGo+W5enOmHY/EuiV3DMME8AqjSYiTiw4LKWGoUBq+9HUM8GW3sdEXUnFx0gq3J
   38.65 +sx/W06SuX7gmKpnIT8eg3KH7WV8WD8XgoA+cXQRcRvNYEgorBgEEAZdVAQUBAQdA
   38.66 +66eYEm3rUShDU+2xPEGUXTOYGGI1p8E+nNhJXlIgYA4DAQgHAAD/Z5sKGEhd6yYC
   38.67 +2eVNfdWkPEQsBUx1fo8stBzoO0ImLKANrokBNgQYAQgAIBYhBKLACxJmDMtXWea/
   38.68 +GFQxXSnRBuaTBQJcRvNYAhsMAAoJEFQxXSnRBuaTEp4IALFhWfIW8MZjXMRDbhlV
   38.69 +tJ5IwbpXCxuGKzsitYYTmEo6IpxexPfNv1zEX+p6TzPE18bM3bTvY0YWq/nJK5VI
   38.70 +sVxat6d2yCi0/435daQuUkhzkznlWk8BNaGSGvXJta9uhHY61lT/QxvVBhxVf68P
   38.71 +TZbtWnE2Vo+SO4iyNU16/A5VEwIi4B+7BZpNyj3obZUHO2dcR3XSHIPkg0VYOu2P
   38.72 +UmWqBjze9tvzCGS57XJI2CbifVX2hReadFqCOeyy+PGkS28BU/CZEGvQ2IJ2QRJd
   38.73 +yz2t+snKNxeGxdrG+9v5vWwamRmW4Yyuko90rrrsOqobh/i7hlmOrZt3rMiUFZD1
   38.74 +WaU=
   38.75 +=Q5MA
   38.76 +-----END PGP PRIVATE KEY BLOCK-----
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/test/test_keys/pub/crappykey_0-26F88D0B_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    39.3 @@ -0,0 +1,13 @@
    39.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    39.5 +
    39.6 +mE0EXEbjwgECAKrQi4nib3fj2QJEFB21fxYXSH0AP48OrK5am/fHIZnorQGQInVE
    39.7 +7/Z3DWLguO6JVGgL22T4HQyHFhq4PCed0r0AEQEAAbQpV2VhayBSU0EgS2V5IDxj
    39.8 +cmFwcHlrZXlfMEBkYXJ0aG1hbWEuY29vbD6IewQTAQIAJQUCXEbjwgUJAAAAAAIb
    39.9 +AwYLAwcICQoGFQIICQoBBBYBAgACGQEACgkQX9b2Uyb4jQuJ/QH/Yub9iPjUXun8
   39.10 +rHcerpT+44MeV5kA/N4HeQy8Ucdnt5v+Y30HelR+NKtHgM3N9WlfnW0p3T9Gh1+h
   39.11 +uOxbuXOnY7hNBFxG48IBAgC6RCV128OxUGyMTu6ezqYB5ukTphHgEqPy7aI73Egx
   39.12 +I7knLwGCSonliFaevk28GBiqssKZa4/1Xod/EuOsSgzFABEBAAGIXwQYAQIACQUC
   39.13 +XEbjwgIbDAAKCRBf1vZTJviNC4O3AgChC8ynK4r5FjXr3pgQMffw3VPIsGgUyZGk
   39.14 +TiOzRvgla2vnm7JBackX0zgWYeKYT91Z1YvUAgaXsOtg5+E/6/tK
   39.15 +=x0Il
   39.16 +-----END PGP PUBLIC KEY BLOCK-----
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/test/test_keys/pub/crappykey_1-0xC508F2B1_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    40.3 @@ -0,0 +1,28 @@
    40.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    40.5 +
    40.6 +mE0EXEblSgECANCN0ls7KiHjDvhNtjEXubECaeG6WUWyiVjylfGd5C3DkCpPw62j
    40.7 +C+5I5iTAwWqhgCYFXx2Taa5bZfxhkyc5sN0AEQEAAbQpV2VhayBSU0EgS2V5IDxj
    40.8 +cmFwcHlrZXlfMUBkYXJ0aG1hbWEuY29vbD6IkgQTAQgAPAUJAAAAAAYLAwcICQoG
    40.9 +FQIICQoBBBYBAgACGQEWIQT3EriK9SXk4yoqJLzRuGE3xQjysQUCXEbmRQIbAQAK
   40.10 +CRDRuGE3xQjysdbTAf9aljQ/Yin9nHuCp36NSJ6Pz0ojFH4U/X9bdg0ObJMy9nB2
   40.11 +kq52dToQVqAAeCrNoM72nUdYpMNK/gjUkAuZWJYCuE0EXEblSgECAKJ6vLeL3tz5
   40.12 +8A5Rp+xe/EfE1o/N3P3/75c2ESDSxQZS4E0zoZaQGOcdbhKwTAyhGqVUNaz29Fh6
   40.13 +P2Sx1XCMAiEAEQEAAYhfBBgBAgAJBQJcRuVKAhsMAAoJENG4YTfFCPKxvJ0B/2Up
   40.14 +jsZ2rfUzz4fL+i6xV5hLLtuGxfTmcSDCYxUO6oBSFixYOCKLJ8Pj4PPdXk2WwAR/
   40.15 +46hX7RiTwKG4VdwlzhC5AQ0EXEbmTQEIAN9yhr8bxHoO0UOcaer6bHnwdJgNmnqp
   40.16 +TprFy6/dQk0e5WQsSndqtjhbcM1bVPvtBN9TRNu2V5KskHkIGi9hT6tinwb8RpiM
   40.17 +mP2IqBB4TG775dDZFoPCIUgT2N9ttHMmEV5z1T3ihFrRZMgeK2tjFgY7prLm8SPJ
   40.18 +Yy8OHLXtZ1pgjGq/lfWr9FHi+aRPeS+kacSe5kbJdiBrTjQ2V/yXdEUJmX65YjFL
   40.19 +fh7/mWueMG1weyyM50EjTV/iD+5qLunYgU0KIeMwPEjqlGrj0JSNjhQL4W3SWK0B
   40.20 +2tu2zhT5BD+u0XDug+ZVR1n09HCcE95/BqIqpCf5TJxHswUqLH25dGkAEQEAAYkB
   40.21 +rAQYAQgAIBYhBPcSuIr1JeTjKiokvNG4YTfFCPKxBQJcRuZNAhsCAUAJENG4YTfF
   40.22 +CPKxwHQgBBkBCAAdFiEERGu+bZeUOk6WERPaRphZFzO/xKQFAlxG5k0ACgkQRphZ
   40.23 +FzO/xKSCpwgAvKNwZHlTAPkILWmappLE3r99hPfWVAE7p3i69T8rSf/7VhGQiOpF
   40.24 +yrw6u/BGVSWEQ+av0NdQIsxHCHu0fmV4PIhL8sRE2sP0/0yr6vdriJA5Bha43dv2
   40.25 +Iy/EIK4oZ2xwNhPL0l9Ww4d1tr1hX50TBoo0nV3qH6AYHYAebwGCghMhEkeVxH8P
   40.26 +zAKnh+qM8f8XpwaOAVmFRolg7GCNuDzNl07cyGkVcAqy/lsRNAEow+y3SA6Uhmbt
   40.27 +DoH2qTYOqYHh3Ntav9n5rTjwumiLLpbDNnIEnt2rIED48d3krokt/8kSNW1FXayb
   40.28 +ca51vA0r7m43UycutEJ9A4fEKzoHeGZkdKdqAgClDYMTn8TgJd01MSlkwhsqqeni
   40.29 +G/dEU0ZCptOaYs2GsGBobyz69d5LKTqcrEbuafP5MXilLOSQkcfPAxli7j0B
   40.30 +=3gub
   40.31 +-----END PGP PUBLIC KEY BLOCK-----
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/test/test_keys/pub/crappykey_2-0xC027262F_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    41.3 @@ -0,0 +1,13 @@
    41.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    41.5 +
    41.6 +mE0EXEblegECAKrUcuK2FN/qr6tg0OK4IpDky/kJExGaLGGds2LNqSTuTPCHCCQ/
    41.7 +2gbxFYS60M8oaXpax+EWI4sydMzQR4qXo10AEQEAAbQpV2VhayBSU0EgS2V5IDxj
    41.8 +cmFwcHlrZXlfMkBkYXJ0aG1hbWEuY29vbD6IewQTAQIAJQUCXEblegUJAAAAAAIb
    41.9 +AwYLAwcICQoGFQIICQoBBBYBAgACGQEACgkQMld2+8AnJi8WIgH/TQE605yPZac0
   41.10 +fEvzuCTl+k/vOCP1P1FkfsbUm+rzvMnrslso3UFLJIclO9rmQQINl307+fRLXbuZ
   41.11 +1Oy34wgtA7g4BFxG5xASCisGAQQBl1UBBQEBB0Cug/QGjM5TjeKyg6niEHNv+DQZ
   41.12 +LCdFd49RHzSk896aVAMBCAeIdgQYAQgAIBYhBBhURJIFUgeyk2uyFTJXdvvAJyYv
   41.13 +BQJcRucQAhsMAAoJEDJXdvvAJyYvRnMCAJCqixSW4YpifSYsEssPpHKGHVgCR6Fj
   41.14 +LN1yE4Bl0OAra+ocbgEgWY9W91MNi1sV5neaqpyOzuvVRdkAm1i4874=
   41.15 +=ncwA
   41.16 +-----END PGP PUBLIC KEY BLOCK-----
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/test/test_keys/pub/subkey_select_0-0x4929DC45_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    42.3 @@ -0,0 +1,18 @@
    42.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    42.5 +
    42.6 +mQENBFxGBkEBCACxp7qY+FhxQmHicXiVNz65bZxnu8E72iGseEXctVJGv/F3J8DO
    42.7 +RU2mJ+VbKkx3levnCTQPx3Vwg77PSZyu8TJN/Nex9xSypTDo6fMtdOSWLgcKIyIZ
    42.8 ++fcsW61cSs7xgqdx/JaNzmfmXEe7OwoXi0I99BVX//uz1ZWK7nj/YiJs+xuTo5S0
    42.9 +lgWNQ+h0CrbSu4jT8ANMhCHCtqz+biFYATV70Rv3RNz0yVijYQ3h4tuwdONfo9gH
   42.10 +BAoESdhEdk12LJGrgvnY5FKOrx9Q0oHxdmM8Qg66pwd32pram0jeg0cQ3SK8VmBP
   42.11 +vfo24gtKsn4f0oy0jYuxWEgOK1BjNKgepF6FABEBAAG0L1N1YmtleSBDaGVjayAw
   42.12 +IDxzdWJrZXlfc2VsZWN0XzBAZGFydGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcC
   42.13 +BhUKCQgLAgQWAgMBAh4BAheAFiEE8NA8hCwHcMLCqf6vKh7ZgUkp3EUFAlxGCMQC
   42.14 +GyEACgkQKh7ZgUkp3EVWRAf+MCTJZ/gIitYdJsGoYIEm4bs1JO+/lKZFSLoCtxtc
   42.15 +IIFBDqsVhitDC0UtNyuD7TRXanNLXirlOTN/uYKzP/IFiU+q0KoKihNWn7gK7tPd
   42.16 +AQ5uwQZb/7omUZScnfPieurPuKASH4q5XGcqecET05FE/JORxEh57aD3/ILW1Aak
   42.17 +EeKgfC240Z8pEO5bTMda3BV6Va0HGaHsq6GylvzKj2FmcxpbBbrUjxvat4oshTNR
   42.18 +eYHL2C3i4S4hALJCLO2/8pQzNqofitRkn32oR7+PyYgXY2nnjPO7+Mr6J9Jgr237
   42.19 +mzBeq/dAt4qlY5VI8tD1LfVh62tqy96bbenIL8D8xOHWDQ==
   42.20 +=P4RS
   42.21 +-----END PGP PUBLIC KEY BLOCK-----
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/test/test_keys/pub/subkey_select_1-0xF2BFF59E_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    43.3 @@ -0,0 +1,31 @@
    43.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    43.5 +
    43.6 +mQENBFxGBkcBCACzk5CHhKqW0iOYWLo82kQEg+SC61mnxZcwOpad008YbQB/LXRl
    43.7 +4vlxssfZy8upfazux7lMNvz+OlwmGWt+PiVUqZmfWtOkMtKajtXfOj2hXyKOvcib
    43.8 +P42N/D9EGXgo723XAnx0TRRjf2AmP/w/yHkORGBNnLLek6i5J73pnK2x6FtzKITw
    43.9 +8akrX3nwGVhC3DYd1Hf/pdTpl3mp8Lo6bI10rpSMmvcp4/Ie5uJ16LxO04loLAi5
   43.10 +Ic6Q4+YX5WOOPHvdY09w059MXZocuomEmdY8PIvoef954k4+KZWmYpf0SKYOscQc
   43.11 +uznCWTMAQAdRNDjvX49IswRZVBvJYVPHUDGpABEBAAG0L1N1YmtleSBDaGVjayAx
   43.12 +IDxzdWJrZXlfc2VsZWN0XzFAZGFydGhtYW1hLmNvb2w+iQFNBBMBCAA4BQsJCAcC
   43.13 +BhUKCQgLAgQWAgMBAh4BAheAFiEEkYr26Ybzm2MFQeEN9ff6NfK/9Z4FAlxGCiEC
   43.14 +Gy0ACgkQ9ff6NfK/9Z7IZgf4qLkKYeeqOmVk9HARqcyhYYhBrGOF4VaLVW5lJES5
   43.15 +IzK+kT9wc6V0qGrqTqHrlLRCATiVAths/Gyq+eUbHFT68WQ9+2BESyt9/dV36QQy
   43.16 +Q0tdgYK0x6G0anzUYjpwac1zW4M/v5mBDFqhTbfNO8FvRsU6Yctmgw07q3OFpZ6P
   43.17 +BAOXlfalICzZ2RNzRCEOvKhZMuzfUVH/GfXceXBDn5Db1jFkjh4RJCP0XUaAPV+p
   43.18 +w3bO2Sn9Ype3h0dqKE0G5K1QVKbMrH8LACR6WSXbGdjUyB+uXcqnUKBmaIS5p5oK
   43.19 +OMU+xaATM24t651FhOik7uS4gBdvREr6yp1ae05g04eTuI0EXEYKLgEEANrbMRIH
   43.20 +JsXVxPdCqgSgMwvKrS0k6OsRc8UeaQHxMFaNClBkPb2Nc+T5DcQ9UKfbEDegcOF6
   43.21 +hyQ6UglfbtriXat0NOrnBburwLdW7YoBcWayhUDu0QmhIPCb9Xcob8lkQmKzb6bP
   43.22 +85grYoHQWnLfNBfV9qcpHBV+jV2xrOEVCNtZABEBAAGJAesEGAEIACAWIQSRivbp
   43.23 +hvObYwVB4Q319/o18r/1ngUCXEYKLgIbAgC/CRD19/o18r/1nrQgBBkBCAAdFiEE
   43.24 +2aa+R0T4ySVerxrylG24itg63LgFAlxGCi4ACgkQlG24itg63LjdNAQA0AdVfpWI
   43.25 +XG1+VzWVHJ72j8lyQgpoG67UTPks1LZCXiAYLbAn8qOmd30qt75e7PWAfUvISlAU
   43.26 +883k4t+otn8JX3BjBYLwezdKhyWN5kZc6CVxth6TOeVhCyKfh5icfFipOJGEFsxc
   43.27 +Wq3JZtLu4a0mtNb8B3C7vu+dS5LJanv/Nw/CAAgAn+PfQS8Rrwt1ud+4BA/RiDqL
   43.28 +rAOaweAQnRb2l3X6V7vBGBSPnFuEEoLRd5Uqf+4OYICpEclLcZgHDQXcOFf9cKc8
   43.29 +D75OvtESoKNiEWPq+n6YjC+W+FC7s09/BF9gsM8DXq2LgLyTP7uwZM85j/VtGcZB
   43.30 +cNsQUxLyxTL18lxBjTJZXp2P2j/81+NZX1+6N2Omatf1SG2E8CMW+hcllszW+caX
   43.31 +uXq/LpkOw8btqS/tMZrIYhYyD8psWiyxJPZAjqq5fKvTh38bMCb2btGw4pDTlfaC
   43.32 +I4yRZA8UBoqxP/s0BR8XGtJ56sJZIIW+ZpE3Z768J1rgld9yFeilQWkDaI0ZWQ==
   43.33 +=tl7g
   43.34 +-----END PGP PUBLIC KEY BLOCK-----
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/test/test_keys/pub/subkey_select_2-0xBAD7800C_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    44.3 @@ -0,0 +1,28 @@
    44.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    44.5 +
    44.6 +mQENBFxGBkwBCACQa3Qt8LaXvGZ1WL7qJyjeKNd2xW5y6DO8+6Sm6AxEdRSkEg0w
    44.7 +DuceemwhCl8p/VlLsUsqnBXqxR6j4cKGQkSsmvZhZt6EFcPD9/OU1CovcbzylJd1
    44.8 +C8bxFypd2qVpOh0i0lOfhbrtbzCocoDVWZ4rfiMPUWy6E0HGfEcxU8GPMOSIsdbC
    44.9 +vnbZbZrgW8VK8f+vjn4FFrBtMF3Xs1LGwAuzSdTYW68Be7k3MkKKkJl0QrTEzIxo
   44.10 +IEO1EZStmo8VM8nGh0rLe+mQI9TaN/Jn3DCE4m4gmS37hyl4+MPkM7jEc1eJ8DAa
   44.11 +EYpnDoTAs58OBpuHBzsXXvFL/hA5U4rMl9mbABEBAAG0L1N1YmtleSBDaGVjayAy
   44.12 +IDxzdWJrZXlfc2VsZWN0XzJAZGFydGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcC
   44.13 +BhUKCQgLAgQWAgMBAh4BAheAFiEEiJQgLj15HJVWAFi9d2drrLrXgAwFAlxGDH0C
   44.14 +Gy0ACgkQd2drrLrXgAwt4Qf/VbzQFNxLHFqi6x2mffvPR3gUtygMyv3EjlH8VOyD
   44.15 +uDmGu3nCm7Q4LdtjtVhDRYlmwaQHlVp2JxRWDVPUpru7fKxMxk7H39oGoh85VItJ
   44.16 +AyqZZhCbal2FM/W3j/+pnig0Q2kNoCVlD3WZg13Ejw/cw7z4zasaT+O2AJ9KzRNw
   44.17 +4Hk5FEnlhjuSCLdox/oMCe5RM5NmUazC5m4ejpqE/hryLzp10PjCMJCXz2fMrAWM
   44.18 +ZbVWB5vmioP6oR0UjiJdfnEPjjJ7L2w7A08j6kATh4+hPG2FXbox6J3tBJ1flwWc
   44.19 +ZGiTUYEzxPpq3ArOqUEypddkNdrshMQnwSjBJzdFlR4bebgzBFxGDDEWCSsGAQQB
   44.20 +2kcPAQEHQIxutjFIiJAtLbBcHCnXU2jM8JJ8Gz8aGeq2p9KnzVCriQGtBBgBCAAg
   44.21 +FiEEiJQgLj15HJVWAFi9d2drrLrXgAwFAlxGDDECGwIAgQkQd2drrLrXgAx2IAQZ
   44.22 +FggAHRYhBFYfy8bkKp+qd1l15MNU5VghHHKeBQJcRgwxAAoJEMNU5VghHHKeYUUA
   44.23 +/i9CMTiPeDX3rkNU+EwymZ8nWWE6apNkGMHuK8NYgM85AP99KrlJgtElgWcdPbtY
   44.24 +QW63QOXAO7z8gfGx7H8XTShDAtw8B/0djEwYkaKFoOg/MRRlcJMGGMKhUmlqHsk9
   44.25 +7k0rzQO1Gf4ea5DKgW7FQcspVBvlCRabx2JlCTT8t/YNp31Bm20PJwrkQp9tVYTp
   44.26 +OVLxsJsmQa6G0/ypwl49PkaWjXFCsnrgJvwyiHdeSKFaCBl2o7sQoQXGukPFsNcu
   44.27 +OirZ6Z0czdV+O0zCoub5MVtTWA33CiZZK5xOobnb4/Pih1rNEMLu+wfr6s+XjHKf
   44.28 ++CMEEmbwcXG/DV6GhM0WrFQ4iCJx+cNWwnNyffRwLQpg9EUpqXl0Ey6F0J6iApuP
   44.29 +r8c6yvkiI+dNeXeDuwcUgeYc+xgOz8IobCqROh4QWTNOazChvCSx
   44.30 +=xnz/
   44.31 +-----END PGP PUBLIC KEY BLOCK-----
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/test/test_keys/pub/subkey_select_3-0x34F44C02_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    45.3 @@ -0,0 +1,46 @@
    45.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    45.5 +
    45.6 +mQENBFxGBk8BCACikTVRrTEv3Ak3GBm6qNvODY2/P6gksIGgFCqWf6igu2xcBFq/
    45.7 +lNSVXTWUBSHKJUTXujizohDj+uu8ptRxiB9pIjCED10rP0pFhknYRXVInfx6uxGE
    45.8 +ToZ30VymvyVFw1RiHd4Fxg7fg3ri4+8rli+DxcgpiXySusibasnWjrUJMBDXMFl9
    45.9 +LpKCXaS7HNuNQqNYImbM2x3X3q66XOgPb7VIzj8nqdCugASTrCOMZvVytGghPATl
   45.10 +03JzFDPmzbVyxQaGPCqOe9eLVsy+YEvQaZ86qPUiJuEJ/7+ScwvB++kjWi/J6qTR
   45.11 +4SeghWPJr63DYwy6Xo6cx8Bkvhriy+JnYIrvABEBAAG0L1N1YmtleSBDaGVjayAz
   45.12 +IDxzdWJrZXlfc2VsZWN0XzNAZGFydGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcC
   45.13 +BhUKCQgLAgQWAgMBAh4BAheAFiEEXqX39xuzm095JNHo0RxnYTT0TAIFAlxGDVwC
   45.14 +GyEACgkQ0RxnYTT0TAJHfgf/S01scxkskxHWeXwUfVeb/iYbX86TtIB+AJfsiw5H
   45.15 +avSQVdH2gU9m6ZSm/yxM9+WRU4uARaiXRd2HXCMwqx3IIkPjNlNSyB2xyTLdsddC
   45.16 +r0+Tfw09ELbgqn9xZk2d4+EB52QO2D7sYfjV6Rd/HBtEfvihr0DZtXQA76TTl3dM
   45.17 +UVPP/lq/FmaGFaFEROtnAKkOnLhvcNAQVFuVmZ0cZRR21r4qeoblOvSHAWqMSSQ6
   45.18 +H0f/xkPJj7qOqGoBRSjyPdLBogQeYaIQTDChtya2WCEqKTF1qPsGyUCLYJW4ieFL
   45.19 +XirfQqFkuGgh3sflWSwF3CYH3/m6w3j7aAuVXTVQjb3qk7gzBFxGDV4WCSsGAQQB
   45.20 +2kcPAQEHQK1WjaIbAxPLWtVDwrGsBTXx5xmsPko0/7acLzBEPGu5iQGtBBgBCAAg
   45.21 +FiEEXqX39xuzm095JNHo0RxnYTT0TAIFAlxGDV4CGwIAgQkQ0RxnYTT0TAJ2IAQZ
   45.22 +FggAHRYhBKgClKGfPYyj93Zig1osmZQB2tUkBQJcRg1eAAoJEFosmZQB2tUkwqQB
   45.23 +AIYs3W3Sr/Y+k8falIaPFXsXH4lVNWc7Mkmo6BuWKBm+AQD3KD5ch7fZ++mnFrke
   45.24 +P2JXKsBvEdK39IxrloC6hKcCCbVLCACJ1bmu2kKCZ0oPe4SHSCndouekmrHlZ5OT
   45.25 +DntsiDMei7O0X1q8I/8B2DyPCNRS3tKwehE03oPzDxABxV6V/cVuoe0IWtScy15Y
   45.26 +AF1steg4eDVzyX6ach8O3XhCg5CzMFiE4B0YK3t/KHZDaxkLBIjGwiVUrt3+mNnZ
   45.27 +RUEZ/ACvFUccvBwGEkD+DQzoF57QCTqCLF1FxXnr5w1v9L6xsxcLVE9HbUPSlOKQ
   45.28 +S/J1GGcWjNwuY5IBSPbBzp3RQC+ZWY/Ubx+GDKNJnUcjS2eqEuC5tjAsqKeemOR0
   45.29 +XTIWqrQSvSE0s8hszjVQQ2PkFDK5yax8xX0aR7A+dZjj4w/n4q0yuDgEXEYNkxIK
   45.30 +KwYBBAGXVQEFAQEHQOvpNNqX3I+2BFMDqUmk0JxrWUhlSuVjutd3pAZTXHEOAwEI
   45.31 +B4kBNgQYAQgAIBYhBF6l9/cbs5tPeSTR6NEcZ2E09EwCBQJcRg2TAhsMAAoJENEc
   45.32 +Z2E09EwCwcEH/0SbbY68yVsQJm07TU2FK7N83vlyzdLv1zeB65dFq/4P2tPmlfHO
   45.33 ++o7t4xy0SvTaonXnYiorsyS/HdSs4GqTQYwaeu0YT67rESKZaOmAIIEmIOWbjy+s
   45.34 +6i3vWWdHr4XZbVHgkTR3oMCw1VS6fMcNE940D3UrlRqiPPIrtv4KNX9Yvwso88Mw
   45.35 +zVZ2MwmKM2bKxdfgkcgbALGpPOResVoCK+AOyamdVFCAAHGZT1FNu7MxQMN0C/3Q
   45.36 +acX3o5VyvgGDrDN/9Xl3q4H1sciaOidAgCFwPvbQmzrl2yGyUXhHX3UMA+r5HtYn
   45.37 +Fk8K17IeGbd2WoNbF6tT3uvaWFFUr4JR2JS4jQRcRg2qAQQA1LNWmbgSHrqI3T8v
   45.38 +YGg/18Cf5B9klY4UWuAj3VsdBJVxp0ZJwzmk/N+0b2XTuWd8iPlHuGn4Plqk/zf+
   45.39 +C9YuWOtXUCuRGlQeBuTs5LVgV2QeFf/Q7+mZHOmxOPO2gTlPI7S3TcQRaB0nLYSU
   45.40 +K/11EHHMtauy3LZtmdqzazKdJm8AEQEAAYkBNgQYAQgAIBYhBF6l9/cbs5tPeSTR
   45.41 +6NEcZ2E09EwCBQJcRg2qAhsMAAoJENEcZ2E09EwChmIH/itKIJcHk8kwBCELYHcD
   45.42 +mlhAvnaQ/3n6u7hWMBQg2alZv+m7JydAidO7dp8qwUdFX+kEwFFuTXIje7s0a37H
   45.43 +dESvXgov+Tl7ar4y2FA+vQePXeMBOhmxz372FnOUOXZ+6N7yrHT2EvBnSqqaQCbs
   45.44 +vNKWIwt6i3+qvX12KgpKx0lYl05Kmwe0RS3S07TBtwFeV8Tk1E3Xtsf0qA5vUvXX
   45.45 +kG+SVaWCU/UCmUi9YhzreKLvowKiFbpK2H9CIs6ZUGpLq2uRDHJhrQY4aeRIGQLx
   45.46 +OfzYww/wAyUaCl0XKRv7zFg28cJwImsk8jcAEJqYZ7YMEf9ohvNNwxdzrrr7zI/6
   45.47 +u3E=
   45.48 +=Pkm5
   45.49 +-----END PGP PUBLIC KEY BLOCK-----
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/test/test_keys/pub/subkey_select_4-0x6E6C7B8A_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    46.3 @@ -0,0 +1,35 @@
    46.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    46.5 +
    46.6 +mQENBFxGBlIBCADQ0BAuaVLY6qVfirbMzGVE9o7T9vJcRuLU5UaQe2xVS/qswu6T
    46.7 +q078R4ItAOItaSUhP081MMZNHCZmMHtJvnkgGCQfGdUnUntbx/McetnNHanXOFtX
    46.8 +51H6rBT2t+0kFQ1FcofG3jXlOgEi3ISqv2MBfkhFG+feVmc1uCcxp4A2pFp+cLhv
    46.9 +nWIJ7ksvKyGM+tbQOIpY+ylYcFWDqCzSZ2nv97U0GMVY4cuKEZpGB8ArPec8X7EM
   46.10 +WSbM6rCHsWSdIO4XrwYazQZeBnIUAN44h76SkSdNuSqJgasXNmJFaMoZtZ8JrcCQ
   46.11 +Zrre+z6CBDr+Zsn5PoqK16TcYZKxRv1Q5MczABEBAAG0L1N1YmtleSBDaGVjayA0
   46.12 +IDxzdWJrZXlfc2VsZWN0XzRAZGFydGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcC
   46.13 +BhUKCQgLAgQWAgMBAh4BAheAFiEEHg0nhkTi4pOp6VPZrJf2f25se4oFAlxG8bsC
   46.14 +Gy0ACgkQrJf2f25se4rBFgf9GFyVdylvzmkeHcf2AyL/+9xXtwhIowp45RWBwyYu
   46.15 +m4kpbeHa7pBBBCYthDRFpIE+G22MCf1cPEjoGqvRbBO2AusozVeqQ2kQ4+Cb2aC8
   46.16 +I2Em5+7aFgUSN0VLEKi/9n8eMu0zWBVZo+QCGOXAZ03tlvatBd+awNniXQii3G49
   46.17 +roOdGzdv5v4hA/hyCl3IqIaJIpRKz1gEh8EpkapJveTYCVH7azZZubunX1O7cOuD
   46.18 +xs5IOZWQBijiXA6jXsqMI06VJjX/UVeUViQbywmlTjnRwImAyZsWPDByCPR362Ar
   46.19 ++Y4k1iwgw9TDnqmnWiCBT6NwaWFlVjmCWavVGuU/tUWjm7gzBFxG8cAWCSsGAQQB
   46.20 +2kcPAQEHQPT1C2N0d7S7xVo9hp05oHdabF9O7OFbOFzljC3GdIwdiQE2BCgBCAAg
   46.21 +FiEEHg0nhkTi4pOp6VPZrJf2f25se4oFAlxG8fMCHQMACgkQrJf2f25se4q/LwgA
   46.22 +oV1vgQCI1nYqem7u94QlS0cVTlGoraffpi3m45bJiWaUy8i992edbItmjyf1Xtm+
   46.23 +JZvMg5DKWNAL7wAYRbOZ97znzxwWJKYA7dn6+Avca2n3LsM56sZArWXxVkNO2G/2
   46.24 +TTRCJaVJhE1KJpfnV424Jfp7T+2bbMz95JlPeWaAWB+oWbntLdxVytvSE6nSBURX
   46.25 +srI5ZN3p9XAc6gfRJAkwSG/lCJZ77Vs3iyPfmZIP9uYUWEnMYHK0LlfGZoXLnLkS
   46.26 +P8zfqBM53b1HjvIen34JzGs8mUG/+6VFP3pqK3Hz49emVCI+MDWCp/bAtqKOsbdn
   46.27 +sIpPDs/1fXevdNgAy7+yUYkBrQQYAQgAIBYhBB4NJ4ZE4uKTqelT2ayX9n9ubHuK
   46.28 +BQJcRvHAAhsCAIEJEKyX9n9ubHuKdiAEGRYIAB0WIQT219vqalJJ1uHNw9p6A734
   46.29 +iJOYXwUCXEbxwAAKCRB6A734iJOYX/nLAP9k0W5isyraHgsTtd9+IHBu9Rt1DXvJ
   46.30 +ssd+QzyANC8kqwD7BmOWI0/1uk3qFkbpjIO885JCrqVig9t3WCi7g1HJMwBUZAf+
   46.31 +POH49X3pQkK8IolZoSv3IZY9aSBJrYRvDWY3MHaZpb41PzdjByR3rXvjt2CGbPkR
   46.32 +O5d8UpcanedbZ/ujMOzZjw/ViHrEyB7Uk3rpkM93rwlnY5rAbmLSvX/2FdYqtwlB
   46.33 +AAuTNhMWKPUiNlAQyJD/WyAADJssc9U55e/ujUXkRnqwJDJtDtEJMUtGQQWNzY6M
   46.34 +h4ff40wx2JsQ9IS3EHPlD6Rb90H1zgQY2mVW4NILz1WIIL40NKLiH3t0+7dlZjpI
   46.35 +vb7grmU4ShUPlcHusEMdpPiHwG8Z7uX0GjHRb/LilePw149z9hl+4QBO1qyp85tJ
   46.36 +NKFdNB/YcgmAbC7FdcBCnQ==
   46.37 +=hOhH
   46.38 +-----END PGP PUBLIC KEY BLOCK-----
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/test/test_keys/pub/subkey_select_5-0xD106E693_pub.asc	Wed Jan 23 11:59:43 2019 +0100
    47.3 @@ -0,0 +1,45 @@
    47.4 +-----BEGIN PGP PUBLIC KEY BLOCK-----
    47.5 +
    47.6 +mQENBFxGBlQBCAC4ZU2FVdlU3ghrsETX/G34YFP7ywiy5cHlayODWygJBOz6w1MI
    47.7 +OiG6tlGzoB7uGMRfByIz00Ry0GoJtm/shyrh2f+qrT5Pqw38SpjJ5PipMndNPaQh
    47.8 +svxWnrpiSpnn/948uqoUHVD/oDjcJQHLVRb1j3fW6oJqV7Z2IjMvhunCtmJ+63fO
    47.9 +M9dsV43oYRcMv13y3rGKsK6OLBuOVNXVbpRKN3Q2oUui2qiVsq4++ABbBQQN9Nft
   47.10 +8poMArL9wLCL2pUB+ZqMhx9SW7bYByyQSdiwZj5CkR6EwNrm73ZIPgByKg5193de
   47.11 +s32DyadnQYbbFQu+YjMgBYekfY8o8LtZEXpfABEBAAG0L1N1YmtleSBDaGVjayA1
   47.12 +IDxzdWJrZXlfc2VsZWN0XzVAZGFydGhtYW1hLmNvb2w+iQFOBBMBCAA4BQsJCAcC
   47.13 +BhUKCQgLAgQWAgMBAh4BAheAFiEEosALEmYMy1dZ5r8YVDFdKdEG5pMFAlxG8xgC
   47.14 +GyMACgkQVDFdKdEG5pOa/ggApoZjV/dIerseQjhRvcmsb8AuCtYIeGJdQsI2vmPv
   47.15 +i2v3sblnHzJN6fqHX1kjW+Anm/47O8Y38iCa/ClGbEzPlNIjt2gbRU2fDMFXs/Y/
   47.16 +uahmJ5im8u1o/5/u99t+Pg8xWngyxSMfbiCUah9+sWV926qXMgAWLQi+WXEth9hJ
   47.17 +HDr0ojnSYZdv7hDj1ja5Ureq+f8cvZN1JlTT5Eek3mUKcCFGT0MgBvCw6oyXuMS2
   47.18 +PhQETx0MLI/A4DZ61I6V3CugmwwIUV8R/fzU/n8lF9X+5To+kyiRhznB/jaqXmG1
   47.19 +bpF+lpxTegbBNcfEAKHhHcj7yuEjzSKSvGu+duxJD+tXHrkBDQRcRvMfAQgA4nTl
   47.20 +PF0e8YPjg8iwsdwjFsBYUPu4Jga2ZKdgMs54LujAs8Hy95JKS5i7Dj58EDzu2WLX
   47.21 +kBXQkm9iYCd9K5dPAdXb56aAqtrb+FXGqvdIAeeVIN/G7m3r3YcqZuypU7K/TsCU
   47.22 +1/l+AWOYi0i7P5b9awVY9gAVTkB9fglKMR7FlISKt4vriwYu3O36BWNx7b2GpsJm
   47.23 +MQVoA0EG9JytnaIorNBjvFu3siJ8PU0SDIhXJUfFVPiGiw0xmikxUB87tBnAhtqs
   47.24 +Hh56KG2zKnfW1thG5YHzPiLkba+uzlXUrbBUxzlY9PXy1dBGR/Uli1xQD9YMtpyy
   47.25 +D7P4r5sHLk5lc/aCTQARAQABiQE2BCgBCAAgFiEEosALEmYMy1dZ5r8YVDFdKdEG
   47.26 +5pMFAlxG81ACHQEACgkQVDFdKdEG5pN1WQf/cYE9+f7Q5aNEK3CtxCIjZ3mqeHio
   47.27 +ItNVW88E5OLbpwfoPCWBVVTTHmOibeHdjjo0P/qZrOMTzkgLfOIiLiyS6D/EHRey
   47.28 +uX2GjXuTFelcccytcOuPOPmJl7yvAVp1wfOwmIX7gvGjXIeqji2Kfv3lFf35g8v4
   47.29 +QQYGsSVG5fczysSsieMJBTpCvYc8Y2MYdk1Uo0h180a448yIaCRnGdM4STXdj/g9
   47.30 +HSwoyGJFCDQx5zes99jRSlmLJAzNALkE+oY0r0QdMHPTVCKVHBrRztZUUkYRAoQ7
   47.31 +hHbErGj8spqtxwBMi8BBDOYrD8dCltGPOH1Lt1HDH3E+Ju4VJwfZH6gbrYkBNgQY
   47.32 +AQgAIBYhBKLACxJmDMtXWea/GFQxXSnRBuaTBQJcRvMfAhsMAAoJEFQxXSnRBuaT
   47.33 +Di0H/jJJ6o2Jf8kX/l5BT8FKvAA+PpWO8BFQEFPMsIJKb/n2PqAc8c+UTizkm+bL
   47.34 +4Dgk8m2lMmluzR55KJr3Arau2BTrHciXNEctVIEeobUC/yIRB0sMX7hKfU0cDSBt
   47.35 +OJoZA5JcSIFoUY4A/I1Suw3FX2uZASepsWPcu8Rj9moNU2lyXoxyb6xvzEr9DLj6
   47.36 +Rc7211VvUnPeXhYRVs/PlMWp06pEzDr63f3CwxxWXvfCOEszIw51OHYrDdGo+W5e
   47.37 +nOmHY/EuiV3DMME8AqjSYiTiw4LKWGoUBq+9HUM8GW3sdEXUnFx0gq3Jsx/W06Su
   47.38 +X7gmKpnIT8eg3KH7WV8WD8XgoA+4OARcRvNYEgorBgEEAZdVAQUBAQdA66eYEm3r
   47.39 +UShDU+2xPEGUXTOYGGI1p8E+nNhJXlIgYA4DAQgHiQE2BBgBCAAgFiEEosALEmYM
   47.40 +y1dZ5r8YVDFdKdEG5pMFAlxG81gCGwwACgkQVDFdKdEG5pMSnggAsWFZ8hbwxmNc
   47.41 +xENuGVW0nkjBulcLG4YrOyK1hhOYSjoinF7E982/XMRf6npPM8TXxszdtO9jRhar
   47.42 ++ckrlUixXFq3p3bIKLT/jfl1pC5SSHOTOeVaTwE1oZIa9cm1r26EdjrWVP9DG9UG
   47.43 +HFV/rw9Nlu1acTZWj5I7iLI1TXr8DlUTAiLgH7sFmk3KPehtlQc7Z1xHddIcg+SD
   47.44 +RVg67Y9SZaoGPN722/MIZLntckjYJuJ9VfaFF5p0WoI57LL48aRLbwFT8JkQa9DY
   47.45 +gnZBEl3LPa36yco3F4bF2sb72/m9bBqZGZbhjK6Sj3Suuuw6qhuH+LuGWY6tm3es
   47.46 +yJQVkPVZpQ==
   47.47 +=00b5
   47.48 +-----END PGP PUBLIC KEY BLOCK-----