2017-04-28 10:06:33 +09:00
|
|
|
/* misc.c - Miscellaneous functions
|
2011-03-01 14:42:56 +01:00
|
|
|
* Copyright (C) 2004, 2009, 2011 Free Software Foundation, Inc.
|
2001-11-07 17:44:22 +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
|
2001-11-07 17:44:22 +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/>.
|
2001-11-07 17:44:22 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <unistd.h>
|
2004-04-13 09:45:35 +00:00
|
|
|
#ifdef HAVE_LOCALE_H
|
|
|
|
#include <locale.h>
|
|
|
|
#endif
|
2001-11-07 17:44:22 +00:00
|
|
|
|
2003-11-12 15:17:44 +00:00
|
|
|
#include "gpgsm.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
#include "../common/i18n.h"
|
|
|
|
#include "../common/sysutils.h"
|
2011-03-01 14:42:56 +01:00
|
|
|
#include "../common/tlv.h"
|
|
|
|
#include "../common/sexp-parse.h"
|
|
|
|
|
2001-11-07 17:44:22 +00:00
|
|
|
|
2004-04-13 09:45:35 +00:00
|
|
|
/* Setup the environment so that the pinentry is able to get all
|
|
|
|
required information. This is used prior to an exec of the
|
|
|
|
protect-tool. */
|
|
|
|
void
|
|
|
|
setup_pinentry_env (void)
|
|
|
|
{
|
2004-12-07 11:21:40 +00:00
|
|
|
#ifndef HAVE_W32_SYSTEM
|
2004-04-13 09:45:35 +00:00
|
|
|
char *lc;
|
2009-07-07 10:02:41 +00:00
|
|
|
const char *name, *value;
|
|
|
|
int iterator;
|
2004-10-04 13:21:37 +00:00
|
|
|
|
|
|
|
/* Try to make sure that GPG_TTY has been set. This is needed if we
|
|
|
|
call for example the protect-tools with redirected stdin and thus
|
|
|
|
it won't be able to ge a default by itself. Try to do it here
|
|
|
|
but print a warning. */
|
2009-07-07 10:02:41 +00:00
|
|
|
value = session_env_getenv (opt.session_env, "GPG_TTY");
|
|
|
|
if (value)
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv ("GPG_TTY", value, 1);
|
2004-10-04 13:21:37 +00:00
|
|
|
else if (!(lc=getenv ("GPG_TTY")) || !*lc)
|
|
|
|
{
|
|
|
|
log_error (_("GPG_TTY has not been set - "
|
|
|
|
"using maybe bogus default\n"));
|
2012-11-20 19:01:13 +01:00
|
|
|
lc = gnupg_ttyname (0);
|
2004-10-04 13:21:37 +00:00
|
|
|
if (!lc)
|
|
|
|
lc = "/dev/tty";
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv ("GPG_TTY", lc, 1);
|
2004-10-04 13:21:37 +00:00
|
|
|
}
|
|
|
|
|
2004-04-13 09:45:35 +00:00
|
|
|
if (opt.lc_ctype)
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv ("LC_CTYPE", opt.lc_ctype, 1);
|
2004-04-13 09:45:35 +00:00
|
|
|
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
|
|
|
else if ( (lc = setlocale (LC_CTYPE, "")) )
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv ("LC_CTYPE", lc, 1);
|
2004-04-13 09:45:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (opt.lc_messages)
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv ("LC_MESSAGES", opt.lc_messages, 1);
|
2004-04-13 09:45:35 +00:00
|
|
|
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
|
|
|
|
else if ( (lc = setlocale (LC_MESSAGES, "")) )
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv ("LC_MESSAGES", lc, 1);
|
2004-04-13 09:45:35 +00:00
|
|
|
#endif
|
2007-11-19 16:03:50 +00:00
|
|
|
|
2009-07-07 10:02:41 +00:00
|
|
|
iterator = 0;
|
|
|
|
while ((name = session_env_list_stdenvnames (&iterator, NULL)))
|
|
|
|
{
|
|
|
|
if (!strcmp (name, "GPG_TTY"))
|
|
|
|
continue; /* Already set. */
|
|
|
|
value = session_env_getenv (opt.session_env, name);
|
|
|
|
if (value)
|
2010-04-14 11:24:02 +00:00
|
|
|
gnupg_setenv (name, value, 1);
|
2009-07-07 10:02:41 +00:00
|
|
|
}
|
2007-11-19 16:03:50 +00:00
|
|
|
|
2004-12-07 11:21:40 +00:00
|
|
|
#endif /*!HAVE_W32_SYSTEM*/
|
2004-04-13 09:45:35 +00:00
|
|
|
}
|
2011-03-01 14:42:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Transform a sig-val style s-expression as returned by Libgcrypt to
|
|
|
|
one which includes an algorithm identifier encoding the public key
|
|
|
|
and the hash algorithm. The public key algorithm is taken directly
|
|
|
|
from SIGVAL and the hash algorithm is given by MDALGO. This is
|
|
|
|
required because X.509 merges the public key algorithm and the hash
|
|
|
|
algorithm into one OID but Libgcrypt is not aware of that. The
|
|
|
|
function ignores missing parameters so that it can also be used to
|
|
|
|
create an siginfo value as expected by ksba_certreq_set_siginfo.
|
|
|
|
To create a siginfo s-expression a public-key s-expression may be
|
|
|
|
used instead of a sig-val. We only support RSA for now. */
|
|
|
|
gpg_error_t
|
|
|
|
transform_sigval (const unsigned char *sigval, size_t sigvallen, int mdalgo,
|
|
|
|
unsigned char **r_newsigval, size_t *r_newsigvallen)
|
|
|
|
{
|
|
|
|
gpg_error_t err;
|
|
|
|
const unsigned char *buf, *tok;
|
|
|
|
size_t buflen, toklen;
|
|
|
|
int depth, last_depth1, last_depth2;
|
|
|
|
int is_pubkey = 0;
|
|
|
|
const unsigned char *rsa_s = NULL;
|
2015-01-05 15:10:03 +01:00
|
|
|
size_t rsa_s_len = 0;
|
2011-03-01 14:42:56 +01:00
|
|
|
const char *oid;
|
|
|
|
gcry_sexp_t sexp;
|
|
|
|
|
|
|
|
*r_newsigval = NULL;
|
|
|
|
if (r_newsigvallen)
|
|
|
|
*r_newsigvallen = 0;
|
|
|
|
|
|
|
|
buf = sigval;
|
|
|
|
buflen = sigvallen;
|
|
|
|
depth = 0;
|
|
|
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
|
|
|
return err;
|
|
|
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
|
|
|
return err;
|
|
|
|
if (tok && toklen == 7 && !memcmp ("sig-val", tok, toklen))
|
|
|
|
;
|
|
|
|
else if (tok && toklen == 10 && !memcmp ("public-key", tok, toklen))
|
|
|
|
is_pubkey = 1;
|
|
|
|
else
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
|
|
|
return err;
|
|
|
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
|
|
|
return err;
|
|
|
|
if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
|
|
|
|
return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
|
|
|
|
|
|
|
|
last_depth1 = depth;
|
|
|
|
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
|
|
|
|
&& depth && depth >= last_depth1)
|
|
|
|
{
|
|
|
|
if (tok)
|
|
|
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
|
|
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
|
|
|
return err;
|
|
|
|
if (tok && toklen == 1)
|
|
|
|
{
|
|
|
|
const unsigned char **mpi;
|
|
|
|
size_t *mpi_len;
|
|
|
|
|
|
|
|
switch (*tok)
|
|
|
|
{
|
|
|
|
case 's': mpi = &rsa_s; mpi_len = &rsa_s_len; break;
|
|
|
|
default: mpi = NULL; mpi_len = NULL; break;
|
|
|
|
}
|
|
|
|
if (mpi && *mpi)
|
|
|
|
return gpg_error (GPG_ERR_DUP_VALUE);
|
|
|
|
|
|
|
|
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
|
|
|
|
return err;
|
|
|
|
if (tok && mpi)
|
|
|
|
{
|
|
|
|
*mpi = tok;
|
|
|
|
*mpi_len = toklen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip to the end of the list. */
|
|
|
|
last_depth2 = depth;
|
|
|
|
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
|
|
|
|
&& depth && depth >= last_depth2)
|
|
|
|
;
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
/* Map the hash algorithm to an OID. */
|
|
|
|
switch (mdalgo)
|
|
|
|
{
|
|
|
|
case GCRY_MD_SHA1:
|
|
|
|
oid = "1.2.840.113549.1.1.5"; /* sha1WithRSAEncryption */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GCRY_MD_SHA256:
|
|
|
|
oid = "1.2.840.113549.1.1.11"; /* sha256WithRSAEncryption */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GCRY_MD_SHA384:
|
|
|
|
oid = "1.2.840.113549.1.1.12"; /* sha384WithRSAEncryption */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GCRY_MD_SHA512:
|
|
|
|
oid = "1.2.840.113549.1.1.13"; /* sha512WithRSAEncryption */
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return gpg_error (GPG_ERR_DIGEST_ALGO);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rsa_s && !is_pubkey)
|
|
|
|
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s(s%b)))",
|
|
|
|
oid, (int)rsa_s_len, rsa_s);
|
|
|
|
else
|
|
|
|
err = gcry_sexp_build (&sexp, NULL, "(sig-val(%s))", oid);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
err = make_canon_sexp (sexp, r_newsigval, r_newsigvallen);
|
|
|
|
gcry_sexp_release (sexp);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|