2010-04-21 17:30:07 +00:00
|
|
|
/* pubkey-enc.c - Process a public key encoded packet.
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
|
|
|
|
* 2010 Free Software Foundation, Inc.
|
2003-01-09 13:29:36 +00:00
|
|
|
*
|
|
|
|
* 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
|
2007-07-04 19:49:40 +00:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-01-09 13:29:36 +00:00
|
|
|
* (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
|
2016-11-05 12:02:19 +01:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-01-09 13:29:36 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2003-06-18 19:56:13 +00:00
|
|
|
|
|
|
|
#include "gpg.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
#include "../common/util.h"
|
2003-01-09 13:29:36 +00:00
|
|
|
#include "packet.h"
|
|
|
|
#include "keydb.h"
|
|
|
|
#include "trustdb.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
#include "../common/status.h"
|
2003-01-09 13:29:36 +00:00
|
|
|
#include "options.h"
|
|
|
|
#include "main.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
#include "../common/i18n.h"
|
2003-06-18 19:56:13 +00:00
|
|
|
#include "pkglue.h"
|
2006-08-16 10:47:53 +00:00
|
|
|
#include "call-agent.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
#include "../common/host2net.h"
|
2017-06-06 16:01:40 +02:00
|
|
|
#include "../common/compliance.h"
|
2006-04-19 11:26:11 +00:00
|
|
|
|
2003-01-09 13:29:36 +00:00
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
static gpg_error_t get_it (ctrl_t ctrl, PKT_pubkey_enc *k,
|
2010-04-23 11:36:59 +00:00
|
|
|
DEK *dek, PKT_public_key *sk, u32 *keyid);
|
2003-01-09 13:29:36 +00:00
|
|
|
|
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
/* Check that the given algo is mentioned in one of the valid user-ids. */
|
2003-01-09 13:29:36 +00:00
|
|
|
static int
|
2010-04-21 17:30:07 +00:00
|
|
|
is_algo_in_prefs (kbnode_t keyblock, preftype_t type, int algo)
|
2003-01-09 13:29:36 +00:00
|
|
|
{
|
2010-04-21 17:30:07 +00:00
|
|
|
kbnode_t k;
|
|
|
|
|
|
|
|
for (k = keyblock; k; k = k->next)
|
|
|
|
{
|
|
|
|
if (k->pkt->pkttype == PKT_USER_ID)
|
|
|
|
{
|
|
|
|
PKT_user_id *uid = k->pkt->pkt.user_id;
|
|
|
|
prefitem_t *prefs = uid->prefs;
|
|
|
|
|
2017-03-08 11:01:22 +01:00
|
|
|
if (uid->created && prefs && !uid->flags.revoked && !uid->flags.expired)
|
2010-04-21 17:30:07 +00:00
|
|
|
{
|
|
|
|
for (; prefs->type; prefs++)
|
|
|
|
if (prefs->type == type && prefs->value == algo)
|
|
|
|
return 1;
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-04-21 17:30:07 +00:00
|
|
|
return 0;
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
/*
|
|
|
|
* Get the session key from a pubkey enc packet and return it in DEK,
|
|
|
|
* which should have been allocated in secure memory by the caller.
|
2003-01-09 13:29:36 +00:00
|
|
|
*/
|
2010-04-21 17:30:07 +00:00
|
|
|
gpg_error_t
|
2015-11-03 23:15:27 +01:00
|
|
|
get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
|
2003-01-09 13:29:36 +00:00
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
PKT_public_key *sk = NULL;
|
2010-04-21 17:30:07 +00:00
|
|
|
int rc;
|
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
if (DBG_CLOCK)
|
|
|
|
log_clock ("get_session_key enter");
|
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC);
|
|
|
|
if (rc)
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
if ((k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets)
|
|
|
|
{
|
|
|
|
sk = xmalloc_clear (sizeof *sk);
|
2010-04-23 11:36:59 +00:00
|
|
|
sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo. */
|
2017-03-31 20:03:52 +02:00
|
|
|
if (!(rc = get_seckey (ctrl, sk, k->keyid)))
|
2017-06-06 16:01:40 +02:00
|
|
|
{
|
2017-08-01 08:41:47 +02:00
|
|
|
/* Check compliance. */
|
|
|
|
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
|
|
|
|
sk->pubkey_algo,
|
|
|
|
sk->pkey, nbits_from_pk (sk), NULL))
|
|
|
|
{
|
|
|
|
log_info (_("key %s is not suitable for decryption"
|
|
|
|
" in %s mode\n"),
|
|
|
|
keystr_from_pk (sk),
|
|
|
|
gnupg_compliance_option_string (opt.compliance));
|
|
|
|
rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rc = get_it (ctrl, k, dek, sk, k->keyid);
|
2017-06-06 16:01:40 +02:00
|
|
|
}
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
2010-04-21 17:30:07 +00:00
|
|
|
else if (opt.skip_hidden_recipients)
|
|
|
|
rc = gpg_error (GPG_ERR_NO_SECKEY);
|
|
|
|
else /* Anonymous receiver: Try all available secret keys. */
|
|
|
|
{
|
|
|
|
void *enum_context = NULL;
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
2011-09-20 19:24:52 +02:00
|
|
|
free_public_key (sk);
|
2010-04-21 17:30:07 +00:00
|
|
|
sk = xmalloc_clear (sizeof *sk);
|
2015-11-03 23:15:27 +01:00
|
|
|
rc = enum_secret_keys (ctrl, &enum_context, sk);
|
2010-04-21 17:30:07 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
2015-01-22 12:06:11 +01:00
|
|
|
rc = GPG_ERR_NO_SECKEY;
|
2010-04-21 17:30:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sk->pubkey_algo != k->pubkey_algo)
|
|
|
|
continue;
|
2010-10-13 15:57:08 +00:00
|
|
|
if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
|
|
|
|
continue;
|
2010-04-23 11:36:59 +00:00
|
|
|
keyid_from_pk (sk, keyid);
|
2011-11-22 15:30:26 +01:00
|
|
|
if (!opt.quiet)
|
|
|
|
log_info (_("anonymous recipient; trying secret key %s ...\n"),
|
|
|
|
keystr (keyid));
|
2010-04-21 17:30:07 +00:00
|
|
|
|
2017-08-01 08:41:47 +02:00
|
|
|
/* Check compliance. */
|
|
|
|
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
|
|
|
|
sk->pubkey_algo,
|
|
|
|
sk->pkey, nbits_from_pk (sk), NULL))
|
|
|
|
{
|
|
|
|
log_info (_("key %s is not suitable for decryption"
|
|
|
|
" in %s mode\n"),
|
|
|
|
keystr_from_pk (sk),
|
|
|
|
gnupg_compliance_option_string (opt.compliance));
|
|
|
|
continue;
|
|
|
|
}
|
2017-06-06 16:01:40 +02:00
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
rc = get_it (ctrl, k, dek, sk, keyid);
|
2010-04-21 17:30:07 +00:00
|
|
|
if (!rc)
|
|
|
|
{
|
2011-11-22 15:30:26 +01:00
|
|
|
if (!opt.quiet)
|
|
|
|
log_info (_("okay, we are the anonymous recipient.\n"));
|
2010-04-21 17:30:07 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-10-13 15:57:08 +00:00
|
|
|
else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
|
|
|
|
break; /* Don't try any more secret keys. */
|
2010-04-21 17:30:07 +00:00
|
|
|
}
|
2015-11-03 23:15:27 +01:00
|
|
|
enum_secret_keys (ctrl, &enum_context, NULL); /* free context */
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
|
|
|
|
2017-06-20 08:31:07 +02:00
|
|
|
leave:
|
2011-09-20 19:24:52 +02:00
|
|
|
free_public_key (sk);
|
2013-01-08 14:44:49 +01:00
|
|
|
if (DBG_CLOCK)
|
|
|
|
log_clock ("get_session_key leave");
|
2010-04-21 17:30:07 +00:00
|
|
|
return rc;
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
static gpg_error_t
|
2017-03-31 20:03:52 +02:00
|
|
|
get_it (ctrl_t ctrl,
|
|
|
|
PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
|
2003-01-09 13:29:36 +00:00
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
gpg_error_t err;
|
2003-07-03 18:08:16 +00:00
|
|
|
byte *frame = NULL;
|
2006-11-21 11:00:14 +00:00
|
|
|
unsigned int n;
|
|
|
|
size_t nframe;
|
2003-07-03 18:08:16 +00:00
|
|
|
u16 csum, csum2;
|
2013-08-26 17:29:54 +02:00
|
|
|
int padding;
|
2010-04-23 11:36:59 +00:00
|
|
|
gcry_sexp_t s_data;
|
|
|
|
char *desc;
|
|
|
|
char *keygrip;
|
2011-01-25 16:54:18 +01:00
|
|
|
byte fp[MAX_FINGERPRINT_LEN];
|
2011-01-05 17:33:17 -08:00
|
|
|
size_t fpn;
|
2003-01-09 13:29:36 +00:00
|
|
|
|
2013-01-08 14:44:49 +01:00
|
|
|
if (DBG_CLOCK)
|
|
|
|
log_clock ("decryption start");
|
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
/* Get the keygrip. */
|
|
|
|
err = hexkeygrip_from_pk (sk, &keygrip);
|
|
|
|
if (err)
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
/* Convert the data to an S-expression. */
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
if (sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|
|
|
|
|| sk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E)
|
2010-04-23 11:36:59 +00:00
|
|
|
{
|
|
|
|
if (!enc->data[0] || !enc->data[1])
|
|
|
|
err = gpg_error (GPG_ERR_BAD_MPI);
|
|
|
|
else
|
2011-02-03 16:31:42 +01:00
|
|
|
err = gcry_sexp_build (&s_data, NULL, "(enc-val(elg(a%m)(b%m)))",
|
2010-04-23 11:36:59 +00:00
|
|
|
enc->data[0], enc->data[1]);
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
else if (sk->pubkey_algo == PUBKEY_ALGO_RSA
|
|
|
|
|| sk->pubkey_algo == PUBKEY_ALGO_RSA_E)
|
2003-07-03 18:08:16 +00:00
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
if (!enc->data[0])
|
|
|
|
err = gpg_error (GPG_ERR_BAD_MPI);
|
|
|
|
else
|
|
|
|
err = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))",
|
|
|
|
enc->data[0]);
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
else if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
2011-01-10 20:24:14 -08:00
|
|
|
{
|
|
|
|
if (!enc->data[0] || !enc->data[1])
|
|
|
|
err = gpg_error (GPG_ERR_BAD_MPI);
|
|
|
|
else
|
2011-01-31 15:44:24 +01:00
|
|
|
err = gcry_sexp_build (&s_data, NULL, "(enc-val(ecdh(s%m)(e%m)))",
|
2014-04-28 10:36:16 +09:00
|
|
|
enc->data[1], enc->data[0]);
|
2011-01-10 20:24:14 -08:00
|
|
|
}
|
2010-04-23 11:36:59 +00:00
|
|
|
else
|
|
|
|
err = gpg_error (GPG_ERR_BUG);
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
goto leave;
|
|
|
|
|
2011-02-03 16:31:42 +01:00
|
|
|
if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
|
|
|
{
|
|
|
|
fingerprint_from_pk (sk, fp, &fpn);
|
2016-04-29 11:05:24 +02:00
|
|
|
log_assert (fpn == 20);
|
2011-02-03 16:31:42 +01:00
|
|
|
}
|
2011-01-05 17:33:17 -08:00
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
/* Decrypt. */
|
2017-03-31 20:03:52 +02:00
|
|
|
desc = gpg_format_keydesc (ctrl, sk, FORMAT_KEYDESC_NORMAL, 1);
|
2013-02-07 20:37:58 +01:00
|
|
|
err = agent_pkdecrypt (NULL, keygrip,
|
|
|
|
desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
|
2013-08-26 17:29:54 +02:00
|
|
|
s_data, &frame, &nframe, &padding);
|
2010-04-23 11:36:59 +00:00
|
|
|
xfree (desc);
|
|
|
|
gcry_sexp_release (s_data);
|
|
|
|
if (err)
|
|
|
|
goto leave;
|
2003-07-03 18:08:16 +00:00
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
/* Now get the DEK (data encryption key) from the frame
|
|
|
|
*
|
2017-02-20 16:19:50 -05:00
|
|
|
* Old versions encode the DEK in this format (msb is left):
|
2010-04-21 17:30:07 +00:00
|
|
|
*
|
|
|
|
* 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2
|
|
|
|
*
|
|
|
|
* Later versions encode the DEK like this:
|
|
|
|
*
|
|
|
|
* 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
|
|
|
|
*
|
|
|
|
* (mpi_get_buffer already removed the leading zero).
|
|
|
|
*
|
|
|
|
* RND are non-zero randow bytes.
|
|
|
|
* A is the cipher algorithm
|
|
|
|
* DEK is the encryption key (session key) with length k
|
|
|
|
* CSUM
|
|
|
|
*/
|
2015-04-06 13:07:09 +02:00
|
|
|
if (DBG_CRYPTO)
|
2010-04-21 17:30:07 +00:00
|
|
|
log_printhex ("DEK frame:", frame, nframe);
|
|
|
|
n = 0;
|
2011-01-05 17:33:17 -08:00
|
|
|
|
2011-01-21 12:00:57 +01:00
|
|
|
if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
|
|
|
{
|
|
|
|
gcry_mpi_t shared_mpi;
|
|
|
|
gcry_mpi_t decoded;
|
2011-01-25 16:54:18 +01:00
|
|
|
|
2011-01-21 12:00:57 +01:00
|
|
|
/* At the beginning the frame are the bytes of shared point MPI. */
|
|
|
|
err = gcry_mpi_scan (&shared_mpi, GCRYMPI_FMT_USG, frame, nframe, NULL);
|
|
|
|
if (err)
|
|
|
|
{
|
2011-01-25 16:54:18 +01:00
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
2011-01-21 12:00:57 +01:00
|
|
|
goto leave;
|
|
|
|
}
|
2011-01-10 20:24:14 -08:00
|
|
|
|
2011-01-21 12:00:57 +01:00
|
|
|
err = pk_ecdh_decrypt (&decoded, fp, enc->data[1]/*encr data as an MPI*/,
|
|
|
|
shared_mpi, sk->pkey);
|
|
|
|
mpi_release (shared_mpi);
|
|
|
|
if(err)
|
|
|
|
goto leave;
|
2011-01-10 20:24:14 -08:00
|
|
|
|
2015-08-06 17:00:41 +09:00
|
|
|
xfree (frame);
|
|
|
|
err = gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, decoded);
|
2011-01-21 12:00:57 +01:00
|
|
|
mpi_release (decoded);
|
|
|
|
if (err)
|
|
|
|
goto leave;
|
2011-01-10 20:24:14 -08:00
|
|
|
|
2011-01-21 12:00:57 +01:00
|
|
|
/* Now the frame are the bytes decrypted but padded session key. */
|
2011-01-10 20:24:14 -08:00
|
|
|
|
2011-01-21 12:00:57 +01:00
|
|
|
/* Allow double padding for the benefit of DEK size concealment.
|
|
|
|
Higher than this is wasteful. */
|
2011-01-25 16:54:18 +01:00
|
|
|
if (!nframe || frame[nframe-1] > 8*2 || nframe <= 8
|
|
|
|
|| frame[nframe-1] > nframe)
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
2011-01-25 16:54:18 +01:00
|
|
|
goto leave;
|
2011-01-21 12:00:57 +01:00
|
|
|
}
|
|
|
|
nframe -= frame[nframe-1]; /* Remove padding. */
|
2016-04-29 11:05:24 +02:00
|
|
|
log_assert (!n); /* (used just below) */
|
2011-01-21 12:00:57 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-08-26 17:29:54 +02:00
|
|
|
if (padding)
|
2011-01-21 12:00:57 +01:00
|
|
|
{
|
|
|
|
if (n + 7 > nframe)
|
|
|
|
{
|
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
|
|
|
goto leave;
|
|
|
|
}
|
2019-04-03 15:30:10 +02:00
|
|
|
|
|
|
|
/* FIXME: Actually the leading zero is required but due to
|
|
|
|
* the way we encode the output in libgcrypt as an MPI we
|
|
|
|
* are not able to encode that leading zero. However, when
|
|
|
|
* using a Smartcard we are doing it the right way and
|
|
|
|
* therefore we have to skip the zero. This should be fixed
|
|
|
|
* in gpg-agent of course. */
|
|
|
|
if (!frame[n])
|
|
|
|
n++;
|
|
|
|
|
2011-01-21 12:00:57 +01:00
|
|
|
if (frame[n] == 1 && frame[nframe - 1] == 2)
|
|
|
|
{
|
|
|
|
log_info (_("old encoding of the DEK is not supported\n"));
|
|
|
|
err = gpg_error (GPG_ERR_CIPHER_ALGO);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
if (frame[n] != 2) /* Something went wrong. */
|
|
|
|
{
|
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
for (n++; n < nframe && frame[n]; n++) /* Skip the random bytes. */
|
|
|
|
;
|
|
|
|
n++; /* Skip the zero byte. */
|
|
|
|
}
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
2010-04-21 17:30:07 +00:00
|
|
|
|
|
|
|
if (n + 4 > nframe)
|
|
|
|
{
|
2011-01-21 12:00:57 +01:00
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
2010-04-21 17:30:07 +00:00
|
|
|
goto leave;
|
2003-07-03 18:08:16 +00:00
|
|
|
}
|
2006-04-19 11:26:11 +00:00
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
dek->keylen = nframe - (n + 1) - 2;
|
|
|
|
dek->algo = frame[n++];
|
2010-04-23 11:36:59 +00:00
|
|
|
err = openpgp_cipher_test_algo (dek->algo);
|
|
|
|
if (err)
|
2010-04-21 17:30:07 +00:00
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
if (!opt.quiet && gpg_err_code (err) == GPG_ERR_CIPHER_ALGO)
|
2010-04-21 17:30:07 +00:00
|
|
|
{
|
|
|
|
log_info (_("cipher algorithm %d%s is unknown or disabled\n"),
|
|
|
|
dek->algo,
|
|
|
|
dek->algo == CIPHER_ALGO_IDEA ? " (IDEA)" : "");
|
|
|
|
}
|
|
|
|
dek->algo = 0;
|
|
|
|
goto leave;
|
2003-07-03 18:08:16 +00:00
|
|
|
}
|
2010-04-21 17:30:07 +00:00
|
|
|
if (dek->keylen != openpgp_cipher_get_algo_keylen (dek->algo))
|
2006-04-19 11:26:11 +00:00
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
2010-04-21 17:30:07 +00:00
|
|
|
goto leave;
|
|
|
|
}
|
2003-01-09 13:29:36 +00:00
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
/* Copy the key to DEK and compare the checksum. */
|
2015-02-11 10:27:57 +01:00
|
|
|
csum = buf16_to_u16 (frame+nframe-2);
|
2010-04-21 17:30:07 +00:00
|
|
|
memcpy (dek->key, frame + n, dek->keylen);
|
|
|
|
for (csum2 = 0, n = 0; n < dek->keylen; n++)
|
|
|
|
csum2 += dek->key[n];
|
|
|
|
if (csum != csum2)
|
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
err = gpg_error (GPG_ERR_WRONG_SECKEY);
|
2010-04-21 17:30:07 +00:00
|
|
|
goto leave;
|
|
|
|
}
|
2013-01-08 14:44:49 +01:00
|
|
|
if (DBG_CLOCK)
|
|
|
|
log_clock ("decryption ready");
|
2015-04-06 13:07:09 +02:00
|
|
|
if (DBG_CRYPTO)
|
2010-04-21 17:30:07 +00:00
|
|
|
log_printhex ("DEK is:", dek->key, dek->keylen);
|
2003-01-09 13:29:36 +00:00
|
|
|
|
2017-02-23 19:59:21 +01:00
|
|
|
/* Check that the algo is in the preferences and whether it has
|
|
|
|
* expired. Also print a status line with the key's fingerprint. */
|
2010-04-21 17:30:07 +00:00
|
|
|
{
|
|
|
|
PKT_public_key *pk = NULL;
|
2017-02-23 19:59:21 +01:00
|
|
|
PKT_public_key *mainpk = NULL;
|
2017-03-31 20:03:52 +02:00
|
|
|
KBNODE pkb = get_pubkeyblock (ctrl, keyid);
|
2003-01-09 13:29:36 +00:00
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
if (!pkb)
|
|
|
|
{
|
2010-04-23 11:36:59 +00:00
|
|
|
err = -1;
|
2010-04-21 17:30:07 +00:00
|
|
|
log_error ("oops: public key not found for preference check\n");
|
|
|
|
}
|
|
|
|
else if (pkb->pkt->pkt.public_key->selfsigversion > 3
|
|
|
|
&& dek->algo != CIPHER_ALGO_3DES
|
|
|
|
&& !opt.quiet
|
|
|
|
&& !is_algo_in_prefs (pkb, PREFTYPE_SYM, dek->algo))
|
|
|
|
log_info (_("WARNING: cipher algorithm %s not found in recipient"
|
|
|
|
" preferences\n"), openpgp_cipher_algo_name (dek->algo));
|
2017-02-23 19:59:21 +01:00
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
if (!err)
|
2010-04-21 17:30:07 +00:00
|
|
|
{
|
2017-02-23 19:59:21 +01:00
|
|
|
kbnode_t k;
|
|
|
|
int first = 1;
|
2010-04-21 17:30:07 +00:00
|
|
|
|
|
|
|
for (k = pkb; k; k = k->next)
|
|
|
|
{
|
|
|
|
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
{
|
|
|
|
u32 aki[2];
|
|
|
|
|
2017-02-23 19:59:21 +01:00
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
first = 0;
|
|
|
|
mainpk = k->pkt->pkt.public_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
keyid_from_pk (k->pkt->pkt.public_key, aki);
|
2010-04-21 17:30:07 +00:00
|
|
|
if (aki[0] == keyid[0] && aki[1] == keyid[1])
|
|
|
|
{
|
|
|
|
pk = k->pkt->pkt.public_key;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!pk)
|
|
|
|
BUG ();
|
|
|
|
if (pk->expiredate && pk->expiredate <= make_timestamp ())
|
|
|
|
{
|
2014-10-10 15:29:42 +02:00
|
|
|
log_info (_("Note: secret key %s expired at %s\n"),
|
2010-04-21 17:30:07 +00:00
|
|
|
keystr (keyid), asctimestamp (pk->expiredate));
|
|
|
|
}
|
|
|
|
}
|
2003-01-09 13:29:36 +00:00
|
|
|
|
2010-10-20 11:33:50 +00:00
|
|
|
if (pk && pk->flags.revoked)
|
2010-04-21 17:30:07 +00:00
|
|
|
{
|
2014-10-10 15:29:42 +02:00
|
|
|
log_info (_("Note: key has been revoked"));
|
2010-04-21 17:30:07 +00:00
|
|
|
log_printf ("\n");
|
2017-03-31 20:03:52 +02:00
|
|
|
show_revocation_reason (ctrl, pk, 1);
|
2010-04-21 17:30:07 +00:00
|
|
|
}
|
|
|
|
|
2017-02-23 19:59:21 +01:00
|
|
|
if (is_status_enabled () && pk && mainpk)
|
|
|
|
{
|
|
|
|
char pkhex[MAX_FINGERPRINT_LEN*2+1];
|
|
|
|
char mainpkhex[MAX_FINGERPRINT_LEN*2+1];
|
|
|
|
|
|
|
|
hexfingerprint (pk, pkhex, sizeof pkhex);
|
|
|
|
hexfingerprint (mainpk, mainpkhex, sizeof mainpkhex);
|
|
|
|
|
2017-02-28 20:28:56 +01:00
|
|
|
/* Note that we do not want to create a trustdb just for
|
|
|
|
* getting the ownertrust: If there is no trustdb there can't
|
|
|
|
* be ulitmately trusted key anyway and thus the ownertrust
|
|
|
|
* value is irrelevant. */
|
2017-02-23 19:59:21 +01:00
|
|
|
write_status_printf (STATUS_DECRYPTION_KEY, "%s %s %c",
|
2017-02-28 20:28:56 +01:00
|
|
|
pkhex, mainpkhex,
|
2017-03-31 20:03:52 +02:00
|
|
|
get_ownertrust_info (ctrl, mainpk, 1));
|
2017-02-23 19:59:21 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
release_kbnode (pkb);
|
2010-04-23 11:36:59 +00:00
|
|
|
err = 0;
|
2010-04-21 17:30:07 +00:00
|
|
|
}
|
2003-07-03 18:08:16 +00:00
|
|
|
|
2010-04-23 11:36:59 +00:00
|
|
|
leave:
|
2010-04-21 17:30:07 +00:00
|
|
|
xfree (frame);
|
2010-04-23 11:36:59 +00:00
|
|
|
xfree (keygrip);
|
|
|
|
return err;
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-21 17:30:07 +00:00
|
|
|
/*
|
2003-01-09 13:29:36 +00:00
|
|
|
* Get the session key from the given string.
|
|
|
|
* String is supposed to be formatted as this:
|
|
|
|
* <algo-id>:<even-number-of-hex-digits>
|
|
|
|
*/
|
2010-04-21 17:30:07 +00:00
|
|
|
gpg_error_t
|
|
|
|
get_override_session_key (DEK *dek, const char *string)
|
2003-01-09 13:29:36 +00:00
|
|
|
{
|
2010-04-21 17:30:07 +00:00
|
|
|
const char *s;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!string)
|
2015-01-22 12:06:11 +01:00
|
|
|
return GPG_ERR_BAD_KEY;
|
2010-04-21 17:30:07 +00:00
|
|
|
dek->algo = atoi (string);
|
|
|
|
if (dek->algo < 1)
|
2015-01-22 12:06:11 +01:00
|
|
|
return GPG_ERR_BAD_KEY;
|
2010-04-21 17:30:07 +00:00
|
|
|
if (!(s = strchr (string, ':')))
|
2015-01-22 12:06:11 +01:00
|
|
|
return GPG_ERR_BAD_KEY;
|
2010-04-21 17:30:07 +00:00
|
|
|
s++;
|
|
|
|
for (i = 0; i < DIM (dek->key) && *s; i++, s += 2)
|
|
|
|
{
|
|
|
|
int c = hextobyte (s);
|
|
|
|
if (c == -1)
|
2015-01-22 12:06:11 +01:00
|
|
|
return GPG_ERR_BAD_KEY;
|
2010-04-21 17:30:07 +00:00
|
|
|
dek->key[i] = c;
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|
2010-04-21 17:30:07 +00:00
|
|
|
if (*s)
|
2015-01-22 12:06:11 +01:00
|
|
|
return GPG_ERR_BAD_KEY;
|
2010-04-21 17:30:07 +00:00
|
|
|
dek->keylen = i;
|
|
|
|
return 0;
|
2003-01-09 13:29:36 +00:00
|
|
|
}
|