Helper for --passphrase-fd [was: Re: Problem with Gnu-PG]
Bernd Jendrissek
berndj at prism.co.za
Thu Mar 1 11:26:07 CET 2001
Matthias Urlichs smurf at noris.de wrote:
> For a pseudo-safe way to do this, I would use a shell script somewhat
> like this one:
>
> #!/bin/sh
> echo -n "Passphrase: "; stty -echo; read pp; stty echo; echo ""
>
> for i in "$@" ; do ## each recipient
> echo "$i ..."
> echo "$pp" | gpg --passphrase-fd 0 --batch --whatever-other-arguments-"$i"
> done
>
> .. except that this is insecure, as the passphrase might end up in the
> swap file.
Here's my solution, I hope I've done it right! Please tell if I haven't.
Needs a bit of assembly, very little. This is for i386:
/*
* sec_cat.c - secure passphrase copier
*
* Unfortunately, sec_cat causes other pty-writers to get stuck waiting for
* a semaphore to go up. Solved. This was a bug in Linux 2.4.0-testN
* (*** MY OWN KERNEL BUG ***) ;)
*/
#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <termios.h>
#include <unistd.h>
char pass_buf[256];
static char char_translation[256];
static char char_class(const char *buf)
{
int c;
/*
* This has to be in assembler to guarantee that the password never
* leaves its buffer; if even single chars of the password were
* allowed onto the stack (due to a register spill, for instance),
* over time the entire password may be paged out to disk under
* unfavourable conditions. Crackers create these conditions.
*
* The operating system kernel should guarantee that process
* registers are never paged. Linux works this way.
*/
__asm__("movzbl (%1),%0\n"
"movzbl (%2,%0),%0\n"
: "=r" (c)
: "r" (buf), "r" (char_translation));
return ((char) c);
}
int main()
{
struct termios term, rawterm;
unsigned long pts_num, pty_locked;
int ptm, i, m, n;
int got_pass;
int locked = 1;
int input = 0;
ptm = open("/dev/ptmx", O_WRONLY);
if (ptm == -1) {
fprintf(stderr, "Cannot open /dev/ptmx\n");
return 1;
}
if (ioctl(ptm, TIOCGPTN, &pts_num)) {
fprintf(stderr, "Cannot get slave tty number\n");
return 1;
}
pty_locked = 0;
if (ioctl(ptm, TIOCSPTLCK, &pty_locked)) {
fprintf(stderr, "Cannot unlock pty slave\n");
return 1;
}
if (mlock(pass_buf, sizeof (pass_buf))) {
fprintf(stderr, "Warning: cannot lock password buffer\n");
locked = 0;
}
for (i = 0; i < 256; i++) {
char_translation[i] = 0;
}
/* char_translation[0177] = 0177; */
char_translation[0012] = 0012;
char_translation[0015] = 0015;
input = open("/dev/tty", O_RDWR);
if (input == -1) {
fprintf(stderr, "Cannot open tty\n");
return 1;
}
write(input, "Enter password: ", 16);
if (tcgetattr(input, &term)) {
fprintf(stderr, "Cannot get terminal attributes\n");
return 1;
}
cfmakeraw(&rawterm);
if (tcsetattr(input, TCSADRAIN, &rawterm)) {
fprintf(stderr, "Cannot set raw terminal attributes\n");
return 1;
}
m = 0;
got_pass = 0;
while(got_pass == 0 && m < sizeof (pass_buf) - 1) {
n = read(input, pass_buf + m, sizeof (pass_buf) - m);
if (n == -1) {
fprintf(stderr, "Cannot read from terminal\n");
return 1;
}
for (i = 0; i < n && got_pass == 0; i++) {
/* Must *NOT* use pass_buf[m+i] directly */
switch (char_class(pass_buf + m+i)) {
case 0177:
/* Do allow erasure of password */
case 0012:
case 0015:
m++;
got_pass = 1;
write(input, "\r\n", 2);
break;
default:
m++;
write(input, "*", 1);
}
}
}
n = m;
if (tcsetattr(input, TCSADRAIN, &term)) {
fprintf(stderr, "Cannot restore terminal attributes\n");
return 1;
}
close(input);
fprintf(stdout, "%d\n", pts_num);
/* Become a daemon */
/* fork: make sure we are not a process group leader */
switch (fork()) {
case -1: /* error */
fprintf(stderr, "Cannot fork\n");
return 1;
case 0: /* child */
break;
default: /* parent */
_exit(0);
}
/* Close all fd's we know */
fflush(stdout);
close(0);
close(1);
close(2);
/* This is it! */
if (setsid() == -1) {
return 1;
}
while (1) {
int retval;
for (m = 0; m < n; m += retval) {
retval = write(ptm, pass_buf + m, n - m);
if (retval == -1) {
return 2;
}
}
}
/* Really we should never be here */
if (locked) {
munlock(pass_buf, sizeof (pass_buf));
/* Assume success */
}
return 0;
}
More information about the Gnupg-devel
mailing list