Merge branch 'develop'

master scdtools-0.3.3
Damien Goutte-Gattat 6 years ago
commit 352f17ac97
  1. 2
      AUTHORS
  2. 5
      NEWS
  3. 74
      README.md
  4. 4
      configure.ac
  5. 2
      lib/Makefile.am
  6. 114
      lib/xmem.c
  7. 60
      lib/xmem.h
  8. 2
      man/scdrand.1.in
  9. 2
      man/scdtotp.1.in
  10. 60
      src/gpg-util.c
  11. 2
      src/gpg-util.h
  12. 2
      src/otpauth.c
  13. 24
      src/scdrand.c
  14. 2
      src/scdtotp.c

@ -1 +1 @@
Damien Goutte-Gattat
Damien Goutte-Gattat <dgouttegattat@incenp.org>

@ -1,3 +1,8 @@
Changes in scdtools 0.3.3
* Look for GPG-Agent socket in [/var]/run.
Changes in scdtools 0.3.2
* Add the -e, --entropy-bits option to scdrand.

@ -2,26 +2,52 @@ Scdtools - Tools for Scdaemon and OpenPGP smartcards
====================================================
Scdtools is a set of utility tools to work with Scdaemon, the smartcard
daemon of the GnuPG project, and OpenPGP smartcards.
daemon of the [GnuPG project](http://www.gnupg.org/), and [OpenPGP
smartcards](http://g10code.com/docs/openpgp-card-2.0.pdf).
Scdrand - Extract random numbers from a smartcard
-------------------------------------------------
Scdrand obtains up to 256 bytes of random data from a ISO7816-compliant
_Scdrand_ obtains up to 256 bytes of random data from a ISO7816-compliant
smartcard and adds them to the kernel entropy pool.
It uses Scdaemon to send a `GET CHALLENGE` to the smartcard. As per
ISO 7816-4, the smartcard replies with random bytes, which Scdrand then
ISO 7816-4, the smartcard replies with random bytes, which _scdrand_ then
sends to the Linux kernel entropy pool through the RNDADDENTROPY ioctl
call on `/dev/random`.
Since that call requires root privileges, scdrand is installed with the
setuid bit set. To mitigate risks associated with running as root, the
program forks itself at startup and only the child retains the root
Since that call requires root privileges, _scdrand_ is installed with
the setuid bit set. To mitigate risks associated with running as root,
the program forks itself at startup and only the child retains the root
privileges needed to write to `/dev/random`. The parent process, in
charge of communicating with the smartcard, then runs with the
privileges on the calling user.
### Usage
The most basic usage of _scdrand_ is as follows:
```sh
$ scdrand 32
```
The program will request 32 random bytes from the card, feed them to the
entropy pool, then quits. You can request from 1 to 256 bytes.
With the `-l, --loop` option, _scdrand_ will not quit, but will
periodically request random bytes from the card and feed them to the
pool. With the `-t, --threshold` option, _scdrand_ will attempt to feed
the pool only if the available entropy in the pool falls below a
specified threshold. So in the following example:
```sh
$ scdrand -l -i 1 -t 512 256
```
_scdrand_ will check the state of the entropy pool every second; if
there is less than 512 bits of entropy available, it will feed the pool
with 256 random bytes. The program will quit upon receiving a `^C`
signal.
Scdtotp - Generate time-based OTP from an OpenPGP smartcard
-----------------------------------------------------------
@ -31,20 +57,21 @@ generator token. It generates time-based one-time password (TOTP) as per
expects to find in the private data object of the inserted OpenPGP
smartcard.
Note that contrary to a true password generator token, the key cannot
remain only on the smartcard, it has to be sent to the computer so
that scdtotp can derive the password from it. Thus it cannot provide
the same level of security.
> Contrary to a true password generator token, the key cannot remain
> only on the smartcard, it has to be sent to the computer so that
> scdtotp can derive the password from it. Thus it cannot provide the
> same level of security.
The key must be stored as an `otpauth://` URI as specified in [Google
Authenticator’s wiki](https://code.google.com/p/google-authenticator/wiki/KeyUriFormat),
e.g.:
otpauth://totp/alice@example.org?secret=KIMEFUAW4SRW
```
otpauth://totp/alice@example.org?secret=KIMEFUAW4SRW
```
where the _secret_ parameter is the Base32-encoded key. This format
allows to specify also the non-secret parameters of the TOTP
algorithm:
where the _secret_ parameter is the Base32-encoded key. This format
allows to specify also the non-secret parameters of the TOTP algorithm:
- the HMAC algorithm to use: `&algorithm=mac`, where _mac_ can be `sha1`
(default), `sha256`, or `sha512`;
@ -52,7 +79,13 @@ algorithm:
seconds by default);
- the number of digits to output: `&digits=N` (defaults to 6).
All of these parameters may be overridden by command line options.
> The (undocumented) `privatedo N` command of the GnuPG’s card editor
> may be used to store the URI into the Nth private DO of the OpenPGP
> smartcard.
Once the URI is on the card and the card is inserted in the card reader,
simply calling _scdtotp_ will print the one-time password for the
current time window on standard output.
Copying
@ -62,12 +95,9 @@ License, version 3 or higher. The full license is included in the
[COPYING file](COPYING) of the source distribution.
Homepage and contact
--------------------
The project is located at <http://www.incenp.org/dvlpt/scdrand.html>.
Homepage and repository
-----------------------
The project is located at <https://incenp.org/dvlpt/scdrand.html>.
The latest source code is available in a Git repository at
<git://git.incenp.org/scdrand.git> and may also be browsed at
<http://www.incenp.org/gitweb/?p=scdrand.git;a=summary>.
The author may be contact at the following address:
Damien Goutte-Gattat <dgouttegattat@incenp.org>
<https://incenp.org/dvlpt/gitweb/?p=scdrand.git;a=summary>.

@ -1,6 +1,6 @@
dnl Configure template for the scdrand package
AC_INIT([scdtools], [0.3.2],
AC_INIT([scdtools], [0.3.3],
[dgouttegattat@incenp.org])
AC_CONFIG_SRCDIR([configure.ac])
AC_CONFIG_MACRO_DIR([m4])
@ -45,6 +45,8 @@ AC_DEFINE_UNQUOTED([DEFAULT_PRIVATE_DO], [$with_default_do],
[Default private DO for scdtotp.])
AC_SUBST([DEFAULT_PRIVATE_DO], [$with_default_do])
AC_SUBST([BUILD_DATE], [`date +%Y-%m-%d`])
dnl Output files
AC_CONFIG_FILES([Makefile lib/Makefile src/Makefile
man/Makefile man/scdrand.1 man/scdtotp.1])

@ -1,5 +1,5 @@
noinst_LIBRARIES = libscdrand.a
libscdrand_a_SOURCES = err.compat.h compat.h xmem.c xmem.h
libscdrand_a_SOURCES = err.compat.h compat.h
libscdrand_a_LIBADD = $(LIBOBJS)

@ -1,114 +0,0 @@
/*
* xmem - Incenp.org Notch Library: die-on-error memory functions
* Copyright (C) 2011 Damien Goutte-Gattat
*
* This program 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.
*
* This program 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 <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <xmem.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
void (*xmem_error)(const char *, unsigned int) = NULL;
#define mem_error(f, l) \
do { \
if ( xmem_error ) \
(*xmem_error)((f), (l)); \
err(EXIT_FAILURE, "%s, %d", (f), (l)); \
} while ( 0 )
void *
do_malloc(size_t s, const char *file, unsigned int line)
{
void *p;
if ( ! (p = malloc(s)) && s )
mem_error(file, line);
return p;
}
void *
do_calloc(size_t n, size_t s, const char *file, unsigned int line)
{
void *p;
if ( ! (p = calloc(n, s)) && n && s )
mem_error(file, line);
return p;
}
void *
do_realloc(void *p, size_t s, const char *file, unsigned int line)
{
void *np;
if ( ! (np = realloc(p, s)) && s )
mem_error(file, line);
return np;
}
char *
do_strdup(const char *s, const char *file, unsigned int line)
{
char *dup;
if ( ! (dup = strdup(s)) && s )
mem_error(file, line);
return dup;
}
int
do_asprintf(char **s,
const char *fmt,
const char *file,
unsigned int line,
...)
{
int ret;
va_list ap;
va_start(ap, line);
ret = vasprintf(s, fmt, ap);
va_end(ap);
if ( ret == -1 )
mem_error(file, line);
return ret;
}
int
do_vasprintf(char **s,
const char *fmt,
const char *file,
unsigned int line,
va_list ap)
{
int ret;
if ( (ret = vasprintf(s, fmt, ap)) == -1 )
mem_error(file, line);
return ret;
}

@ -1,60 +0,0 @@
/*
* xmem - Incenp.org Notch Library: die-on-error memory functions
* Copyright (C) 2011 Damien Goutte-Gattat
*
* This program 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.
*
* This program 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ICP20110203_XMEM_H
#define ICP20110203_XMEM_H
#include <stdlib.h>
#include <stdarg.h>
#ifdef __cpluscplus
extern "C" {
#endif
extern void (*xmem_error)(const char *, unsigned int);
void *
do_malloc(size_t, const char *, unsigned int);
void *
do_calloc(size_t, size_t, const char *, unsigned int);
void *
do_realloc(void *, size_t, const char *, unsigned int);
char *
do_strdup(const char *, const char *, unsigned int);
int
do_asprintf(char **, const char *, const char *, unsigned int, ...);
int
do_vasprintf(char **, const char *, const char *, unsigned int, va_list);
#define xmalloc(s) do_malloc(s, __FILE__, __LINE__)
#define xcalloc(n,s) do_calloc(n, s, __FILE__, __LINE__)
#define xrealloc(p,s) do_realloc(p, s, __FILE__, __LINE__)
#define xstrdup(s) do_strdup(s, __FILE__, __LINE__)
#define xasprintf(s,f,...) do_asprintf(s, f, __FILE__, __LINE__, __VA_ARGS__)
#define xvasprintf(s,f,v) do_vasprintf(s, f, __FILE__, __LINE__, v)
#ifdef __cplusplus
}
#endif
#endif /* !ICP20110203_XMEM_H */

@ -1,4 +1,4 @@
.TH SCDRAND 11/08/2014 "scdtools @PACKAGE_VERSION@"
.TH SCDRAND @BUILD_DATE@ "scdtools @PACKAGE_VERSION@"
.SH NAME
scdrand \- Extract random numbers from a smartcard

@ -1,4 +1,4 @@
.TH SCDTOTP 18/12/2014 "scdtools @PACKAGE_VERSION@"
.TH SCDTOTP @BUILD_DATE@ "scdtools @PACKAGE_VERSION@"
.SH NAME
scdtotp \- Generate one-time passwords from an OpenPGP smartcard

@ -1,6 +1,6 @@
/*
* scdtools - Tools for Scdaemon and OpenPGP smartcards
* Copyright (C) 2014 Damien Goutte-Gattat
* Copyright (C) 2014,2015,2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -50,6 +50,8 @@ static char *
get_agent_socket_name(void)
{
char *env_info, *socket_name = NULL;
char buf[255] = "";
struct stat st;
/* First look for GPG_AGENT_INFO in the environment. */
if ( (env_info = getenv("GPG_AGENT_INFO")) ) {
@ -66,11 +68,11 @@ get_agent_socket_name(void)
*colon_index = '\0';
}
}
else {
/* Then look for the standard socket. */
char buf[255] = "";
if ( ! socket_name ) {
/* Then look for the standard socket
* in GnuPG's home directory. */
struct passwd *pwd;
struct stat st;
if ( (env_info = getenv("GNUPGHOME")) )
snprintf(buf, sizeof(buf), "%s/S.gpg-agent", env_info);
@ -82,24 +84,40 @@ get_agent_socket_name(void)
/* Check whether the socket does exist. */
if ( *buf && stat(buf, &st) != -1 && S_ISSOCK(st.st_mode) )
socket_name = strdup(buf);
else {
/*
* Finally, try to ask the agent directly. This method could
* replace the two above, but since it requires spawning a
* new process, we use it only as a fallback. We expect that
* most of the time, the agent should already be running when
* our programs are called, and thus the socket would already
* exist and be found by the above code.
*/
FILE *f;
}
f = popen("gpg-connect-agent 'GETINFO socket_name' /bye", "r");
if ( f ) {
if ( fscanf(f, "D %254s\nOK\n", buf) == 1 )
socket_name = strdup(buf);
if ( ! socket_name ) {
/* Then look for the standard socket outside of GnuPG's
* home directory (for GnuPG >= 2.1.17). */
static const char *prefixes[] = { "/run", "/var/run", NULL };
int i;
for ( i = 0; prefixes[i] && ! socket_name ; i++ ) {
snprintf(buf, sizeof(buf), "%s/user/%u/gnupg/S.gpg-agent",
prefixes[i], getuid());
if ( stat(buf, &st) != -1 && S_ISSOCK(st.st_mode) )
socket_name = strdup(buf);
}
}
pclose(f);
}
if ( ! socket_name ) {
/*
* Finally, try to ask the agent directly. This method could
* replace all the methods above, but since it requires spawing
* a 0new process, we use it only as a fallback. We expect that
* most of the time, the agent should already be running when
* our programs are called, and thus the socket would already
* exist and be found by the above code.
*/
FILE *f;
f = popen("gpg-connect-agent 'GETINFO socket_name' /bye", "r");
if ( f ) {
if ( fscanf(f, "D %254s\nOK\n", buf) == 1 )
socket_name = strdup(buf);
pclose(f);
}
}

@ -1,6 +1,6 @@
/*
* scdtools - Tools for Scdaemon and OpenPGP smartcards
* Copyright (C) 2014 Damien Goutte-Gattat
* Copyright (C) 2014,2015 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

@ -1,6 +1,6 @@
/*
* scdtools - Tools for Scdaemon and OpenPGP smartcards
* Copyright (C) 2015 Damien Goutte-Gattat
* Copyright (C) 2015,2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

@ -1,6 +1,6 @@
/*
* scdtools - Tools for Scdaemon and OpenPGP smartcards
* Copyright (C) 2014,2015 Damien Goutte-Gattat
* Copyright (C) 2014,2015,2016 Damien Goutte-Gattat
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -37,7 +37,6 @@
#include <gcrypt.h>
#include "xmem.h"
#include "gpg-util.h"
#define MAX_RANDOM_BYTES 256
@ -87,7 +86,7 @@ info(void)
{
printf("\
scdrand (scdtools %s)\n\
Copyright (C) 2014,2015 Damien Goutte-Gattat\n\
Copyright (C) 2016 Damien Goutte-Gattat\n\
\n\
This program is released under the GNU General Public License.\n\
See the COPYING file or <http://www.gnu.org/licenses/gpl.html>.\n\
@ -112,13 +111,12 @@ struct challenge
gpg_error_t
get_challenge_data_cb(void *arg, const void *line, size_t len)
{
struct challenge *c;
unsigned i;
struct challenge *c = arg;
c = (struct challenge *)arg;
if ( len > c->len )
return gpg_error(GPG_ERR_INV_LENGTH);
for ( i = 0; i < len && i < c->len; i++ )
c->data[i] = ((const unsigned char *)line)[i];
memcpy(c->data, line, len);
c->len = len;
return 0;
@ -207,18 +205,19 @@ start_privileged_process(unsigned factor)
if ( (pid = fork()) == 0 ) {
int random_fd, n;
char buffer[MAX_RANDOM_BYTES];
char buffer[sizeof(struct rand_pool_info) + MAX_RANDOM_BYTES], *ptr;
struct rand_pool_info *rpi;
rpi = (struct rand_pool_info *)buffer;
ptr = (char *) &(rpi->buf[0]);
close(fd[1]);
if ( (random_fd = open("/dev/random", O_RDONLY)) == -1 )
err(EXIT_FAILURE, "Cannot open /dev/random");
rpi = xmalloc(sizeof(struct rand_pool_info) + MAX_RANDOM_BYTES);
while ( 1 ) {
n = read(fd[0], buffer, sizeof(buffer));
n = read(fd[0], ptr, MAX_RANDOM_BYTES);
if ( n == -1 )
err(EXIT_FAILURE, "Cannot read from pipe");
@ -228,7 +227,6 @@ start_privileged_process(unsigned factor)
rpi->entropy_count = n * factor;
rpi->buf_size = n;
memcpy(&(rpi->buf[0]), buffer, n);
if ( ioctl(random_fd, RNDADDENTROPY, rpi) == -1 )
warn("Cannot add entropy");

@ -79,7 +79,7 @@ info(void)
{
printf("\
scdtotp (scdtools %s)\n\
Copyright (C) 2014,2015 Damien Goutte-Gattat\n\
Copyright (C) 2016 Damien Goutte-Gattat\n\
\n\
This program is released under the GNU General Public License.\n\
See the COPYING file or <http://www.gnu.org/licenses/gpl.html>.\n\

Loading…
Cancel
Save