diff --git a/Makefile.am b/Makefile.am index 6a2508b11..6ee94561a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -87,6 +87,11 @@ scd = scd else scd = endif +if BUILD_TKDAEMON +tkd = tkd +else +tkd = +endif if BUILD_G13 g13 = g13 else @@ -114,7 +119,7 @@ tpm2d = endif SUBDIRS = m4 common regexp kbx \ - ${gpg} ${sm} ${agent} ${scd} ${g13} ${dirmngr} \ + ${gpg} ${sm} ${agent} ${scd} ${tkd} ${g13} ${dirmngr} \ tools po ${doc} ${tests} ${tpm2d} dist_doc_DATA = README diff --git a/configure.ac b/configure.ac index c31ae026a..a9509b2e5 100644 --- a/configure.ac +++ b/configure.ac @@ -125,6 +125,7 @@ GNUPG_BUILD_PROGRAM(gpgsm, yes) # The agent is a required part and can't be disabled anymore. build_agent=yes GNUPG_BUILD_PROGRAM(scdaemon, yes) +GNUPG_BUILD_PROGRAM(tkdaemon, yes) GNUPG_BUILD_PROGRAM(g13, no) GNUPG_BUILD_PROGRAM(dirmngr, yes) GNUPG_BUILD_PROGRAM(keyboxd, yes) @@ -1840,6 +1841,7 @@ AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes") AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes") AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes") AM_CONDITIONAL(BUILD_SCDAEMON, test "$build_scdaemon" = "yes") +AM_CONDITIONAL(BUILD_TKDAEMON, test "$build_tkdaemon" = "yes") AM_CONDITIONAL(BUILD_G13, test "$build_g13" = "yes") AM_CONDITIONAL(BUILD_DIRMNGR, test "$build_dirmngr" = "yes") AM_CONDITIONAL(BUILD_KEYBOXD, test "$build_keyboxd" = "yes") @@ -2088,6 +2090,7 @@ g10/Makefile sm/Makefile agent/Makefile scd/Makefile +tkd/Makefile tpm2d/Makefile g13/Makefile dirmngr/Makefile diff --git a/tkd/Makefile.am b/tkd/Makefile.am new file mode 100644 index 000000000..b6c30eccb --- /dev/null +++ b/tkd/Makefile.am @@ -0,0 +1,44 @@ +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is part of GnuPG. +# +# GnuPG is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# GnuPG is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# SPDX-License-Identifier: GPL-3.0-or-later + +EXTRA_DIST = + +# libexec_PROGRAMS = tkdaemon + +noinst_PROGRAMS = pksign + +AM_CPPFLAGS = + +AM_CFLAGS = $(LIBGCRYPT_CFLAGS) \ + $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS) + +include $(top_srcdir)/am/cmacros.am + +tkdaemon_SOURCES = \ + tkdaemon.c tkdaemon.h \ + command.c + +tkdaemon_LDADD = $(libcommonpth) \ + $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ + $(GPG_ERROR_LIBS) \ + $(LIBINTL) $(DL_LIBS) $(NETLIBS) $(LIBICONV) + +pksign_LDADD = $(libcommonpth) \ + $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \ + $(GPG_ERROR_LIBS) \ + $(LIBINTL) $(DL_LIBS) $(NETLIBS) $(LIBICONV) diff --git a/tkd/pksign.c b/tkd/pksign.c index ade6bfe7d..7995d9ed4 100644 --- a/tkd/pksign.c +++ b/tkd/pksign.c @@ -1,34 +1,57 @@ +#include #include #include #include #include +#include #include +#include "../common/util.h" #include "pkcs11.h" -/* - * For now, we don't COMPUTE_KEYGRIP, assuming Scute. - * ... which used the ID as keygrip. - */ - -#ifdef COMPUTE_KEYGRIP static void compute_keygrip_rsa (char *keygrip, const char *modulus, unsigned long modulus_len, const char *exponent, unsigned long exponent_len) { - ; + gpg_error_t err; + gcry_sexp_t s_pkey = NULL; + const char *format = "(public-key(rsa(n%b)(e%b)))"; + unsigned char grip[20]; + + err = gcry_sexp_build (&s_pkey, NULL, format, + (int)modulus_len, modulus, + (int)exponent_len, exponent); + if (!err && !gcry_pk_get_keygrip (s_pkey, grip)) + err = gpg_error (GPG_ERR_INTERNAL); + else + { + gcry_sexp_release (s_pkey); + bin2hex (grip, 20, keygrip); + } } static void -compute_keygrip_ec (char *keygrip, - const char *oid, unsigned long oid_len, - const char *ecpoint, unsigned long ecpoing_len) +compute_keygrip_ec (char *keygrip, const char *curve, + const char *ecpoint, unsigned long ecpoint_len) { - ; + gpg_error_t err; + gcry_sexp_t s_pkey = NULL; + const char *format = "(public-key(ecc(curve %s)(q%b)))"; + unsigned char grip[20]; + + err = gcry_sexp_build (&s_pkey, NULL, format, curve, (int)ecpoint_len, + ecpoint); + if (!err && !gcry_pk_get_keygrip (s_pkey, grip)) + err = gpg_error (GPG_ERR_INTERNAL); + else + { + gcry_sexp_release (s_pkey); + bin2hex (grip, 20, keygrip); + } } -#endif + #define ck_function_list _CK_FUNCTION_LIST #define ck_token_info _CK_TOKEN_INFO @@ -50,7 +73,6 @@ compute_keygrip_ec (char *keygrip, * session -> key_list -> key * */ -#define KEYGRIP_LEN (40+1) /* * Major use cases: @@ -72,9 +94,12 @@ struct key { struct token *token; /* Back pointer. */ int valid; ck_object_handle_t p11_keyid; - char keygrip[KEYGRIP_LEN]; + char keygrip[2*KEYGRIP_LEN+1]; int key_type; - /* Possibly, ID, LABEL, etc. */ + unsigned char label[256]; + unsigned long label_len; + unsigned char id[256]; + unsigned long id_len; /* Allowed mechanisms??? */ }; @@ -178,7 +203,7 @@ struct p11dev { int d; }; -static struct p11dev priv; +static struct p11dev p11_priv; static unsigned long notify_cb (ck_session_handle_t session, @@ -205,7 +230,7 @@ open_session (struct token *token) session_flags = session_flags | CKF_SERIAL_SESSION; err = ck->f->C_OpenSession (slot_id, session_flags, - (void *)&priv, notify_cb, &session_handle); + (void *)&p11_priv, notify_cb, &session_handle); if (err) { printf ("open_session: %d\n", err); @@ -271,31 +296,123 @@ logout (struct token *token) } static long -detect_key (int try_private, struct token *token) +examine_public_key (struct token *token, struct key *k, unsigned long keytype, + int update_keyid, ck_object_handle_t obj) +{ + unsigned long err = 0; + struct cryptoki *ck = token->ck; + unsigned char modulus[1024]; + unsigned char exponent[8]; + unsigned char ecparams[256]; + unsigned char ecpoint[256]; + struct ck_attribute templ[3]; + unsigned long mechanisms[3]; + int i; + + templ[0].type = CKA_ALLOWED_MECHANISMS; + templ[0].pValue = (void *)mechanisms; + templ[0].ulValueLen = sizeof (mechanisms); + + if (keytype == CKK_RSA) + { + k->valid = 1; + if (update_keyid) + k->p11_keyid = obj; + k->key_type = KEY_RSA; + + templ[1].type = CKA_MODULUS; + templ[1].pValue = (void *)modulus; + templ[1].ulValueLen = sizeof (modulus); + + templ[2].type = CKA_PUBLIC_EXPONENT; + templ[2].pValue = (void *)exponent; + templ[2].ulValueLen = sizeof (exponent); + + err = ck->f->C_GetAttributeValue (token->session, obj, templ, 3); + if (err) + { + k->valid = -1; + return 1; + } + + if ((modulus[0] & 0x80)) + { + memmove (modulus+1, modulus, templ[1].ulValueLen); + templ[1].ulValueLen++; + modulus[0] = 0; + } + + /* Found a RSA key. */ + printf ("RSA: %d %d %d\n", + templ[0].ulValueLen, + templ[1].ulValueLen, + templ[2].ulValueLen); + puts ("Public key:"); + compute_keygrip_rsa (k->keygrip, + modulus, templ[1].ulValueLen, + exponent, templ[2].ulValueLen); + puts (k->keygrip); + } + else if (keytype == CKK_EC) + { + char *curve_oid = NULL; + const char *curve; + + k->valid = 1; + if (update_keyid) + k->p11_keyid = obj; + k->key_type = KEY_EC; + + templ[1].type = CKA_EC_PARAMS; + templ[1].pValue = ecparams; + templ[1].ulValueLen = sizeof (ecparams); + + templ[2].type = CKA_EC_POINT; + templ[2].pValue = (void *)ecpoint; + templ[2].ulValueLen = sizeof (ecpoint); + + err = ck->f->C_GetAttributeValue (token->session, obj, templ, 3); + if (err) + { + k->valid = -1; + return 1; + } + + /* Found an ECC key. */ + printf ("ECC: %d %d %d\n", + templ[0].ulValueLen, + templ[1].ulValueLen, + templ[2].ulValueLen); + + curve_oid = openpgp_oidbuf_to_str (ecparams+1, templ[1].ulValueLen-1); + curve = openpgp_oid_to_curve (curve_oid, 1); + xfree (curve_oid); + + puts ("Public key:"); + puts (curve); + compute_keygrip_ec (k->keygrip, curve, ecpoint, templ[2].ulValueLen); + puts (k->keygrip); + } + + return 0; +} + +static long +detect_private_keys (struct token *token) { unsigned long err = 0; struct cryptoki *ck = token->ck; struct ck_attribute templ[8]; - unsigned char label[256]; unsigned long class; - unsigned long key_type; - unsigned long mechanisms[3]; - unsigned char id[256]; - unsigned char modulus[1024]; - unsigned char exponent[8]; - unsigned char ecparams[256]; - unsigned char ecpoint[256]; + unsigned long keytype; unsigned long cnt = 0; ck_object_handle_t obj; int i; - if (try_private) - class = CKO_PRIVATE_KEY; - else - class = CKO_PUBLIC_KEY; + class = CKO_PRIVATE_KEY; templ[0].type = CKA_CLASS; templ[0].pValue = (void *)&class; templ[0].ulValueLen = sizeof (class); @@ -313,6 +430,81 @@ detect_key (int try_private, struct token *token) k->token = token; k->valid = 0; + /* Portable way to get objects... is get it one by one. */ + err = ck->f->C_FindObjects (token->session, &obj, 1, &any); + if (err || any == 0) + break; + + templ[0].type = CKA_KEY_TYPE; + templ[0].pValue = &keytype; + templ[0].ulValueLen = sizeof (keytype); + + templ[1].type = CKA_LABEL; + templ[1].pValue = (void *)k->label; + templ[1].ulValueLen = sizeof (k->label) - 1; + + templ[2].type = CKA_ID; + templ[2].pValue = (void *)k->id; + templ[2].ulValueLen = sizeof (k->id) - 1; + + err = ck->f->C_GetAttributeValue (token->session, obj, templ, 3); + if (err) + { + continue; + } + + cnt++; + + k->label_len = templ[1].ulValueLen; + k->label[k->label_len] = 0; + k->id_len = templ[2].ulValueLen; + k->id[k->id_len] = 0; + + printf ("handle: %ld label: %s key_type: %d id: %s\n", + obj, k->label, keytype, k->id); + + if (examine_public_key (token, k, keytype, 1, obj)) + continue; + } + + token->num_keys = cnt; + err = ck->f->C_FindObjectsFinal (token->session); + if (err) + { + return -1; + } + } +} + +static long +check_public_keys (struct token *token) +{ + unsigned long err = 0; + struct cryptoki *ck = token->ck; + + struct ck_attribute templ[8]; + + unsigned char label[256]; + unsigned long class; + unsigned long keytype; + unsigned char id[256]; + + ck_object_handle_t obj; + int i; + + class = CKO_PUBLIC_KEY; + templ[0].type = CKA_CLASS; + templ[0].pValue = (void *)&class; + templ[0].ulValueLen = sizeof (class); + + err = ck->f->C_FindObjectsInit (token->session, templ, 1); + if (!err) + { + while (TRUE) + { + unsigned long any; + struct key *k = NULL; + /* Portable way to get objects... is get it one by one. */ err = ck->f->C_FindObjects (token->session, &obj, 1, &any); if (err || any == 0) @@ -323,8 +515,8 @@ detect_key (int try_private, struct token *token) templ[0].ulValueLen = sizeof (label); templ[1].type = CKA_KEY_TYPE; - templ[1].pValue = &key_type; - templ[1].ulValueLen = sizeof (key_type); + templ[1].pValue = &keytype; + templ[1].ulValueLen = sizeof (keytype); templ[2].type = CKA_ID; templ[2].pValue = (void *)id; @@ -339,102 +531,31 @@ detect_key (int try_private, struct token *token) label[templ[0].ulValueLen] = 0; id[templ[2].ulValueLen] = 0; - printf ("handle: %ld label: %s key_type: %d id: %s\n", - obj, label, key_type, id); - - templ[0].type = CKA_ALLOWED_MECHANISMS; - templ[0].pValue = (void *)mechanisms; - templ[0].ulValueLen = sizeof (mechanisms); - - if (key_type == CKK_RSA) + /* Locate matching private key. */ + for (i = 0; i < token->num_keys; i++) { - templ[1].type = CKA_MODULUS; - templ[1].pValue = (void *)modulus; - templ[1].ulValueLen = sizeof (modulus); + k = &token->key_list[i]; - templ[2].type = CKA_PUBLIC_EXPONENT; - templ[2].pValue = (void *)exponent; - templ[2].ulValueLen = sizeof (exponent); - - err = ck->f->C_GetAttributeValue (token->session, obj, templ, 3); - if (err) - { - continue; - } - - /* Found a RSA key. */ - printf ("RSA: %d %d %d\n", - templ[0].ulValueLen, - templ[1].ulValueLen, - templ[2].ulValueLen); - puts ("Public key:"); - for (i = 0; i < templ[1].ulValueLen; i++) - { - printf ("%02x", modulus[i]); - if ((i % 16) == 15) - puts (""); - } - puts (""); - - k->valid = 1; - k->p11_keyid = obj; - k->key_type = KEY_RSA; -#ifdef COMPUTE_KEYGRIP - compute_keygrip_rsa (k->keygrip, - modulus, templ[0].ulValueLen, - exponent, templ[1].ulValueLen); -#else - memcpy (k->keygrip, id, 40); - k->keygrip[40] = 0; -#endif - cnt++; + if (k->valid == -1 + && k->label_len == templ[0].ulValueLen + && memcmp (label, k->label, k->label_len) == 0 + && ((keytype == CKK_RSA && k->key_type == KEY_RSA) + || (keytype == CKK_EC && k->key_type == KEY_EC)) + && k->id_len == templ[0].ulValueLen + && memcmp (id, k->id, k->id_len) == 0) + break; } - else if (key_type == CKK_EC) - { - templ[1].type = CKA_EC_PARAMS; - templ[1].pValue = ecparams; - templ[1].ulValueLen = sizeof (ecparams); - templ[2].type = CKA_EC_POINT; - templ[2].pValue = (void *)ecpoint; - templ[2].ulValueLen = sizeof (ecpoint); + if (i == token->num_keys) + continue; - err = ck->f->C_GetAttributeValue (token->session, obj, templ, 3); - if (err) - { - continue; - } + printf ("pub: handle: %ld label: %s key_type: %d id: %s\n", + obj, label, keytype, id); - /* Found an ECC key. */ - printf ("ECC: %d %d %d\n", - templ[0].ulValueLen, - templ[1].ulValueLen, - templ[2].ulValueLen); - puts ("Public key:"); - for (i = 0; i < templ[2].ulValueLen; i++) - { - printf ("%02x", ecpoint[i]); - if ((i % 16) == 15) - puts (""); - } - puts (""); - - k->valid = 1; - k->p11_keyid = obj; - k->key_type = KEY_EC; -#ifdef COMPUTE_KEYGRIP - compute_keygrip_ec (k->keygrip, - ecparams, templ[1].ulValueLen, - ecpoint, templ[2].ulValueLen); -#else - memcpy (k->keygrip, id, 40); - k->keygrip[40] = 0; -#endif - cnt++; - } + if (examine_public_key (token, k, keytype, 0, obj)) + continue; } - token->num_keys = cnt; err = ck->f->C_FindObjectsFinal (token->session); if (err) { @@ -512,13 +633,31 @@ static long learn_keys (struct token *token) { unsigned long err = 0; + int i; + + /* Detect private keys on the token. */ + detect_private_keys (token); + + /* + * In some implementations (EC key on SoftHSMv2, for example), + * public key is not available in CKO_PRIVATE_KEY objects. + * + * So, try to examine CKO_PUBLIC_KEY objects, if it provides + * public keys. + */ + check_public_keys (token); + + for (i = 0; i < token->num_keys; i++) + { + struct key *k = &token->key_list[i]; + + if (k->valid == -1) + k->valid = 0; + } - detect_key (1, token); #if 0 - if (token->num_keys == 0) - detect_key (0, token); -#endif get_certificate (token); +#endif return 0; } @@ -539,9 +678,13 @@ find_key (struct cryptoki *ck, const char *keygrip, struct key **r_key) { struct key *k = &token->key_list[j]; + if (k->valid != 1) + continue; + if (memcmp (k->keygrip, keygrip, 40) == 0) { *r_key = k; + printf ("found a key at %d:%d\n", i, j); return 0; } } @@ -677,6 +820,10 @@ main (int argc, const char *argv[]) unsigned char sig[1024]; unsigned long siglen = sizeof (sig); + printf ("key object id: %d\n", k->p11_keyid); + printf ("key type: %d\n", k->key_type); + puts (k->keygrip); + r = do_pksign (k, "test test", 9, sig, &siglen); if (!r) {