1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

Some changes to suport g13.

This commit is contained in:
Werner Koch 2009-09-30 15:28:38 +00:00
parent c11c23b6ac
commit 27c1b4bef8
37 changed files with 2069 additions and 324 deletions

View file

@ -24,12 +24,19 @@ AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS)
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_PTH_CFLAGS) $(PTH_CFLAGS)
g13_SOURCES = \
g13.c g13.h
g13.c g13.h \
keyblob.h \
utils.c utils.h \
create.c create.h \
call-gpg.c call-gpg.h \
backend.c backend.h \
be-encfs.c be-encfs.h \
be-truecrypt.c be-truecrypt.h
g13_LDADD = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a \
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
$(LIBINTL)
g13_LDADD = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a \
$(LIBGCRYPT_LIBS) $(LIBASSUAN_PTH_LIBS) $(PTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL)

83
g13/backend.c Normal file
View file

@ -0,0 +1,83 @@
/* backend.c - Dispatcher to the various backends.
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "g13.h"
#include "i18n.h"
#include "keyblob.h"
#include "backend.h"
#include "be-encfs.h"
#include "be-truecrypt.h"
static gpg_error_t
no_such_backend (int conttype)
{
log_error ("invalid backend %d given - this is most likely a bug\n",
conttype);
return gpg_error (GPG_ERR_INTERNAL);
}
/* If the backend requires a separate file or directory for the
container, return its name by computing it from FNAME which gives
the g13 filename. The new file name is allocated and stored at
R_NAME, if this is expected to be a directory true is stored at
R_ISDIR. If no detached name is expected or an error occurs NULL
is stored at R_NAME. The function returns 0 on success or an error
code. */
gpg_error_t
be_get_detached_name (int conttype, const char *fname,
char **r_name, int *r_isdir)
{
*r_name = NULL;
*r_isdir = 0;
switch (conttype)
{
case CONTTYPE_ENCFS:
return be_encfs_get_detached_name (fname, r_name, r_isdir);
default:
return no_such_backend (conttype);
}
}
gpg_error_t
be_create_new_keys (int conttype, membuf_t *mb)
{
switch (conttype)
{
case CONTTYPE_ENCFS:
return be_encfs_create_new_keys (mb);
case CONTTYPE_TRUECRYPT:
return be_truecrypt_create_new_keys (mb);
default:
return no_such_backend (conttype);
}
}

32
g13/backend.h Normal file
View file

@ -0,0 +1,32 @@
/* backend.h - Defs for the dispatcher to the various backends.
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#ifndef G13_BACKEND_H
#define G13_BACKEND_H
#include "../common/membuf.h"
gpg_error_t be_get_detached_name (int conttype, const char *fname,
char **r_name, int *r_isdir);
gpg_error_t be_create_new_keys (int conttype, membuf_t *mb);
#endif /*G13_BACKEND_H*/

58
g13/be-encfs.c Normal file
View file

@ -0,0 +1,58 @@
/* be-encfs.c - The EncFS based backend
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "g13.h"
#include "i18n.h"
#include "keyblob.h"
#include "be-encfs.h"
/* See be_get_detached_name for a description. Note that the
dispatcher code makes sure that NULL is stored at R_NAME before
calling us. */
gpg_error_t
be_encfs_get_detached_name (const char *fname, char **r_name, int *r_isdir)
{
char *result;
if (!fname || !*fname)
return gpg_error (GPG_ERR_INV_ARG);
result = strconcat (fname, ".d", NULL);
if (!result)
return gpg_error_from_syserror ();
*r_name = result;
*r_isdir = 1;
return 0;
}
gpg_error_t
be_encfs_create_new_keys (membuf_t *mb)
{
return 0;
}

31
g13/be-encfs.h Normal file
View file

@ -0,0 +1,31 @@
/* be-encfs.h - Public defs for the EncFS based backend
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#ifndef G13_BE_ENCFS_H
#define G13_BE_ENCFS_H
#include "backend.h"
gpg_error_t be_encfs_get_detached_name (const char *fname,
char **r_name, int *r_isdir);
gpg_error_t be_encfs_create_new_keys (membuf_t *mb);
#endif /*G13_BE_ENCFS_H*/

39
g13/be-truecrypt.c Normal file
View file

@ -0,0 +1,39 @@
/* be-truecrypt.c - The Truecrypt based backend
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "g13.h"
#include "i18n.h"
#include "be-truecrypt.h"
gpg_error_t
be_truecrypt_create_new_keys (membuf_t *mb)
{
(void)mb;
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}

29
g13/be-truecrypt.h Normal file
View file

@ -0,0 +1,29 @@
/* be-truecrypt.h - Public defs for the Truecrypt based backend
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#ifndef G13_BE_TRUECRYPT_H
#define G13_BE_TRUECRYPT_H
#include "backend.h"
gpg_error_t be_truecrypt_create_new_keys (membuf_t *mb);
#endif /*G13_BE_TRUECRYPT_H*/

466
g13/call-gpg.c Normal file
View file

@ -0,0 +1,466 @@
/* call-gpg.c - Communication with the GPG
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include <pth.h>
#include "g13.h"
#include <assuan.h>
#include "i18n.h"
#include "call-gpg.h"
#include "utils.h"
#include "../common/exechelp.h"
/* Fire up a new GPG. Handle the server's initial greeting. Returns
0 on success and stores the assuan context at R_CTX. */
static gpg_error_t
start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
{
gpg_error_t err;
assuan_context_t ctx = NULL;
const char *pgmname;
const char *argv[6];
int no_close_list[5];
int i;
char line[ASSUAN_LINELENGTH];
(void)ctrl;
*r_ctx = NULL;
err = assuan_new (&ctx);
if (err)
{
log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
return err;
}
/* The first time we are used, intialize the gpg_program variable. */
if ( !opt.gpg_program || !*opt.gpg_program )
opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
if (opt.verbose)
log_info (_("no running gpg - starting `%s'\n"), opt.gpg_program);
/* Compute argv[0]. */
if ( !(pgmname = strrchr (opt.gpg_program, '/')))
pgmname = opt.gpg_program;
else
pgmname++;
if (fflush (NULL))
{
err = gpg_error_from_syserror ();
log_error ("error flushing pending output: %s\n", gpg_strerror (err));
return err;
}
i = 0;
argv[i++] = pgmname;
argv[i++] = "--server";
if ((opt.debug & 1024))
argv[i++] = "--debug=1024";
argv[i++] = "-z";
argv[i++] = "0";
argv[i++] = NULL;
i = 0;
if (log_get_fd () != -1)
no_close_list[i++] = log_get_fd ();
no_close_list[i++] = fileno (stderr);
if (input_fd != -1)
no_close_list[i++] = input_fd;
if (output_fd != -1)
no_close_list[i++] = output_fd;
no_close_list[i] = -1;
/* Connect to GPG and perform initial handshaking. */
err = assuan_pipe_connect (ctx, opt.gpg_program, argv, no_close_list);
/* if (!err) */
/* err = assuan_transact (ctx, "OPTION audit-events=1", */
/* NULL, NULL, NULL, NULL, NULL, NULL); */
/* audit_log_ok (ctrl->audit, AUDIT_GPG_READY, err); */
if (err)
{
assuan_release (ctx);
log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
return gpg_error (GPG_ERR_NO_ENGINE);
}
if (input_fd != -1)
{
snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
assuan_release (ctx);
log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
return err;
}
}
if (output_fd != -1)
{
snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
assuan_release (ctx);
log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
return err;
}
}
*r_ctx = ctx;
if (DBG_ASSUAN)
log_debug ("connection to GPG established\n");
return 0;
}
/* Release the assuan context created by start_gpg. */
static void
release_gpg (assuan_context_t ctx)
{
assuan_release (ctx);
}
/* The data passed to the writer_thread. */
struct writer_thread_parms
{
int fd;
const void *data;
size_t datalen;
gpg_error_t *err_addr;
};
/* The thread started by start_writer. */
static void *
writer_thread (void *arg)
{
struct writer_thread_parms *parm = arg;
const char *buffer = parm->data;
size_t length = parm->datalen;
while (length)
{
ssize_t nwritten;
nwritten = pth_write (parm->fd, buffer, length < 4096? length:4096);
if (nwritten < 0)
{
if (errno == EINTR)
continue;
*parm->err_addr = gpg_error_from_syserror ();
break; /* Write error. */
}
length -= nwritten;
buffer += nwritten;
}
if (close (parm->fd))
log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
xfree (parm);
return NULL;
}
/* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD.
On success the thread receives the ownership over FD. The thread
ID is stored at R_TID. WRITER_ERR is the address of an gpg_error_t
variable to receive a possible write error after the thread has
finished. */
static gpg_error_t
start_writer (int fd, const void *data, size_t datalen,
pth_t *r_tid, gpg_error_t *err_addr)
{
gpg_error_t err;
struct writer_thread_parms *parm;
pth_attr_t tattr;
pth_t tid;
*r_tid = NULL;
*err_addr = 0;
parm = xtrymalloc (sizeof *parm);
if (!parm)
return gpg_error_from_syserror ();
parm->fd = fd;
parm->data = data;
parm->datalen = datalen;
parm->err_addr = err_addr;
tattr = pth_attr_new ();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "fd-writer");
tid = pth_spawn (tattr, writer_thread, parm);
if (!tid)
{
err = gpg_error_from_syserror ();
log_error ("error spawning writer thread: %s\n", gpg_strerror (err));
}
else
{
err = 0;
*r_tid = tid;
}
pth_attr_destroy (tattr);
return err;
}
/* The data passed to the reader_thread. */
struct reader_thread_parms
{
int fd;
membuf_t *mb;
gpg_error_t *err_addr;
};
/* The thread started by start_reader. */
static void *
reader_thread (void *arg)
{
struct reader_thread_parms *parm = arg;
char buffer[4096];
int nread;
while ( (nread = pth_read (parm->fd, buffer, sizeof buffer)) )
{
if (nread < 0)
{
if (errno == EINTR)
continue;
*parm->err_addr = gpg_error_from_syserror ();
break; /* Read error. */
}
put_membuf (parm->mb, buffer, nread);
}
if (close (parm->fd))
log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
xfree (parm);
return NULL;
}
/* Fire up a thread to receive data from the file descriptor FD. On
success the thread receives the ownership over FD. The thread ID
is stored at R_TID. After the thread has finished an error from
the thread will be stored at ERR_ADDR. */
static gpg_error_t
start_reader (int fd, membuf_t *mb, pth_t *r_tid, gpg_error_t *err_addr)
{
gpg_error_t err;
struct reader_thread_parms *parm;
pth_attr_t tattr;
pth_t tid;
*r_tid = NULL;
*err_addr = 0;
parm = xtrymalloc (sizeof *parm);
if (!parm)
return gpg_error_from_syserror ();
parm->fd = fd;
parm->mb = mb;
parm->err_addr = err_addr;
tattr = pth_attr_new ();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "fd-reader");
tid = pth_spawn (tattr, reader_thread, parm);
if (!tid)
{
err = gpg_error_from_syserror ();
log_error ("error spawning reader thread: %s\n", gpg_strerror (err));
}
else
{
err = 0;
*r_tid = tid;
}
pth_attr_destroy (tattr);
return err;
}
/* Call GPG to encrypt a block of data.
*/
gpg_error_t
gpg_encrypt_blob (ctrl_t ctrl, const void *plain, size_t plainlen,
void **r_ciph, size_t *r_ciphlen)
{
gpg_error_t err;
assuan_context_t ctx;
int outbound_fds[2] = { -1, -1 };
int inbound_fds[2] = { -1, -1 };
pth_t writer_tid = NULL;
pth_t reader_tid = NULL;
gpg_error_t writer_err, reader_err;
membuf_t reader_mb;
*r_ciph = NULL;
*r_ciphlen = 0;
/* Init the memory buffer to receive the encrypted stuff. */
init_membuf (&reader_mb, 4096);
/* Create two pipes. */
err = gnupg_create_outbound_pipe (outbound_fds);
if (!err)
err = gnupg_create_inbound_pipe (inbound_fds);
if (err)
{
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
goto leave;
}
/* Start GPG and send the INPUT and OUTPUT commands. */
err = start_gpg (ctrl, outbound_fds[0], inbound_fds[1], &ctx);
if (err)
goto leave;
close (outbound_fds[0]); outbound_fds[0] = -1;
close (inbound_fds[1]); inbound_fds[1] = -1;
/* Start a writer thread to feed the INPUT command of the server. */
err = start_writer (outbound_fds[1], plain, plainlen,
&writer_tid, &writer_err);
if (err)
return err;
outbound_fds[1] = -1; /* The thread owns the FD now. */
/* Start a reader thread to eat from the OUTPUT command of the
server. */
err = start_reader (inbound_fds[0], &reader_mb,
&reader_tid, &reader_err);
if (err)
return err;
outbound_fds[0] = -1; /* The thread owns the FD now. */
/* Run the encryption. */
err = assuan_transact (ctx, "RECIPIENT alpha@example.net",
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("the engine's RECIPIENT command failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
goto leave;
}
err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
log_error ("the engine's ENCRYPT command failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
goto leave;
}
/* Wait for reader and return the data. */
if (!pth_join (reader_tid, NULL))
{
err = gpg_error_from_syserror ();
log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
goto leave;
}
reader_tid = NULL;
if (reader_err)
{
err = reader_err;
log_error ("read error in reader thread: %s\n", gpg_strerror (err));
goto leave;
}
/* Wait for the writer to catch a writer error. */
if (!pth_join (writer_tid, NULL))
{
err = gpg_error_from_syserror ();
log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
goto leave;
}
writer_tid = NULL;
if (writer_err)
{
err = writer_err;
log_error ("write error in writer thread: %s\n", gpg_strerror (err));
goto leave;
}
/* Return the data. */
*r_ciph = get_membuf (&reader_mb, r_ciphlen);
if (!*r_ciph)
{
err = gpg_error_from_syserror ();
log_error ("error while storing the data in the reader thread: %s\n",
gpg_strerror (err));
goto leave;
}
leave:
if (reader_tid)
{
pth_cancel (reader_tid);
pth_join (reader_tid, NULL);
}
if (writer_tid)
{
pth_cancel (writer_tid);
pth_join (writer_tid, NULL);
}
if (outbound_fds[0] != -1)
close (outbound_fds[0]);
if (outbound_fds[1] != -1)
close (outbound_fds[1]);
if (inbound_fds[0] != -1)
close (inbound_fds[0]);
if (inbound_fds[1] != -1)
close (inbound_fds[1]);
release_gpg (ctx);
xfree (get_membuf (&reader_mb, NULL));
return err;
}

29
g13/call-gpg.h Normal file
View file

@ -0,0 +1,29 @@
/* call-gpg.h - Defs for the communication with GPG
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#ifndef G13_CALL_GPG_H
#define G13_CALL_GPG_H
gpg_error_t gpg_encrypt_blob (ctrl_t ctrl,
const void *plain, size_t plainlen,
void **r_ciph, size_t *r_ciphlen);
#endif /*G13_CALL_GPG_H*/

306
g13/create.c Normal file
View file

@ -0,0 +1,306 @@
/* create.c - Create a new crypto container
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#include "g13.h"
#include "i18n.h"
#include "create.h"
#include "keyblob.h"
#include "backend.h"
#include "utils.h"
#include "call-gpg.h"
#include "estream.h"
/* Create a new blob with all the session keys and other meta
information which are to be stored encrypted in the crypto
container header. On success the malloced blob is stored at R_BLOB
and its length at R_BLOBLEN. On error en error ocde is returned
and (R_BLOB,R_BLOBLEN) are set to (NULL,0).
The format of this blob is a sequence of tag-length-value tuples.
All tuples have this format:
2 byte TAG Big endian unsigned integer (0..65535)
described by the KEYBLOB_TAG_ constants.
2 byte LENGTH Big endian unsigned integer (0..65535)
giving the length of the value.
length bytes VALUE The value described by the tag.
The first tag in a keyblob must be a BLOBVERSION. The other tags
depend on the type of the container as described by the CONTTYPE
tag. See keyblob.h for details. */
static gpg_error_t
create_new_keyblob (ctrl_t ctrl, int is_detached,
void **r_blob, size_t *r_bloblen)
{
gpg_error_t err;
unsigned char twobyte[2];
membuf_t mb;
*r_blob = NULL;
*r_bloblen = 0;
init_membuf_secure (&mb, 512);
append_tuple (&mb, KEYBLOB_TAG_BLOBVERSION, "\x01", 1);
twobyte[0] = (ctrl->conttype >> 8);
twobyte[1] = (ctrl->conttype);
append_tuple (&mb, KEYBLOB_TAG_CONTTYPE, twobyte, 2);
if (is_detached)
append_tuple (&mb, KEYBLOB_TAG_DETACHED, NULL, 0);
err = be_create_new_keys (ctrl->conttype, &mb);
if (err)
goto leave;
append_tuple (&mb, KEYBLOB_TAG_FILLER, "filler", 6);
*r_blob = get_membuf (&mb, r_bloblen);
if (!*r_blob)
{
err = gpg_error_from_syserror ();
*r_bloblen = 0;
}
else
log_debug ("used keyblob size is %zu\n", *r_bloblen);
leave:
xfree (get_membuf (&mb, NULL));
return err;
}
/* Encrypt the keyblob (KEYBLOB,KEYBLOBLEN) and store the result at
(R_ENCBLOB, R_ENCBLOBLEN). Returns 0 on success or an error code.
On error R_EKYBLOB is set to NULL. Depending on the keys set in
CTRL the result is a single OpenPGP binary message, a single
special OpenPGP packet encapsulating a CMS message or a
concatenation of both with the CMS packet being the last. */
static gpg_error_t
encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen,
void **r_encblob, size_t *r_encbloblen)
{
gpg_error_t err;
/* FIXME: For now we only implement OpenPGP. */
err = gpg_encrypt_blob (ctrl, keyblob, keybloblen,
r_encblob, r_encbloblen);
return err;
}
/* Write a new file under the name FILENAME with the keyblob and an
appropriate header. This fucntion is called with a lock file in
place and after checking that the filename does not exists. */
static gpg_error_t
write_keyblob (ctrl_t ctrl, const char *filename,
const void *keyblob, size_t keybloblen)
{
gpg_error_t err;
estream_t fp;
unsigned char packet[32];
size_t headerlen, paddinglen;
fp = es_fopen (filename, "wbx");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error ("error creating new container `%s': %s\n",
filename, gpg_strerror (err));
return err;
}
/* Allow for an least 8 times larger keyblob to accommodate for
future key changes. Round it up to 4096 byte. */
headerlen = ((32 + 8 * keybloblen + 16) + 4095) / 4096 * 4096;
paddinglen = headerlen - 32 - keybloblen;
assert (paddinglen >= 16);
packet[0] = (0xc0|61); /* CTB for the private packet type 0x61. */
packet[1] = 0xff; /* 5 byte length packet, value 20. */
packet[2] = 0;
packet[3] = 0;
packet[4] = 0;
packet[5] = 26;
memcpy (packet+6, "GnuPG/G13", 10); /* Packet subtype. */
packet[16] = 1; /* G13 packet format. */
packet[17] = 0; /* Reserved. */
packet[18] = 0; /* Reserved. */
packet[19] = 0; /* OS Flag. */
packet[20] = (headerlen >> 24); /* Total length of header. */
packet[21] = (headerlen >> 16);
packet[22] = (headerlen >> 8);
packet[23] = (headerlen);
packet[24] = 1; /* Number of header copies. */
packet[25] = 0; /* Number of header copies at the end. */
packet[26] = 0; /* Reserved. */
packet[27] = 0; /* Reserved. */
packet[28] = 0; /* Reserved. */
packet[29] = 0; /* Reserved. */
packet[30] = 0; /* Reserved. */
packet[31] = 0; /* Reserved. */
if (es_fwrite (packet, 32, 1, fp) != 1)
goto writeerr;
if (es_fwrite (keyblob, keybloblen, 1, fp) != 1)
goto writeerr;
/* Write the padding. */
packet[0] = (0xc0|61); /* CTB for Private packet type 0x61. */
packet[1] = 0xff; /* 5 byte length packet, value 20. */
packet[2] = (paddinglen-6) >> 24;
packet[3] = (paddinglen-6) >> 16;
packet[4] = (paddinglen-6) >> 8;
packet[5] = (paddinglen-6);
memcpy (packet+6, "GnuPG/PAD", 10); /* Packet subtype. */
if (es_fwrite (packet, 16, 1, fp) != 1)
goto writeerr;
memset (packet, 0, 32);
for (paddinglen-=16; paddinglen >= 32; paddinglen -= 32)
if (es_fwrite (packet, 32, 1, fp) != 1)
goto writeerr;
if (paddinglen)
if (es_fwrite (packet, paddinglen, 1, fp) != 1)
goto writeerr;
if (es_fclose (fp))
{
err = gpg_error_from_syserror ();
log_error ("error closing `%s': %s\n",
filename, gpg_strerror (err));
remove (filename);
return err;
}
return err;
writeerr:
err = gpg_error_from_syserror ();
log_error ("error writing header to `%s': %s\n",
filename, gpg_strerror (err));
es_fclose (fp);
remove (filename);
return err;
}
/* Create a new container under the name FILENAME and intialize it
using the current settings. If the file already exists an error is
returned. */
gpg_error_t
create_new_container (ctrl_t ctrl, const char *filename)
{
gpg_error_t err;
dotlock_t lock;
void *keyblob = NULL;
size_t keybloblen;
void *enckeyblob = NULL;
size_t enckeybloblen;
char *detachedname = NULL;
int detachedisdir;
/* A quick check to see that no container with that name already
exists. */
if (!access (filename, F_OK))
return gpg_error (GPG_ERR_EEXIST);
/* Take a lock and proceed with the creation. If there is a lock we
immediately return an error because for creation it does not make
sense to wait. */
lock = create_dotlock (filename);
if (!lock)
return gpg_error_from_syserror ();
if (make_dotlock (lock, 0))
{
err = gpg_error_from_syserror ();
goto leave;
}
else
err = 0;
/* Check again that the file does not exist. */
{
struct stat sb;
if (!stat (filename, &sb))
{
err = gpg_error (GPG_ERR_EEXIST);
goto leave;
}
}
/* And a possible detached file or directory may not exist either. */
err = be_get_detached_name (ctrl->conttype, filename,
&detachedname, &detachedisdir);
if (err)
goto leave;
if (detachedname)
{
struct stat sb;
if (!stat (detachedname, &sb))
{
err = gpg_error (GPG_ERR_EEXIST);
goto leave;
}
}
/* Create a new keyblob. */
err = create_new_keyblob (ctrl, !!detachedname, &keyblob, &keybloblen);
if (err)
goto leave;
/* Encrypt that keyblob. */
err = encrypt_keyblob (ctrl, keyblob, keybloblen,
&enckeyblob, &enckeybloblen);
if (err)
goto leave;
/* Write out the header, the encrypted keyblob and some padding. */
err = write_keyblob (ctrl, filename, enckeyblob, enckeybloblen);
if (err)
goto leave;
/* Create and append the container. */
leave:
xfree (detachedname);
xfree (enckeyblob);
xfree (keyblob);
destroy_dotlock (lock);
return err;
}

103
g13/g13.c
View file

@ -25,14 +25,18 @@
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <pth.h>
#include "g13.h"
#include <gcrypt.h>
#include <assuan.h>
#include "i18n.h"
#include "sysutils.h"
#include "gc-opt-flags.h"
#include "create.h"
#include "keyblob.h"
enum cmd_and_opt_values {
@ -60,6 +64,8 @@ enum cmd_and_opt_values {
oOutput,
oAgentProgram,
oGpgProgram,
oDisplay,
oTTYname,
oTTYtype,
@ -141,6 +147,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoOptions, "no-options", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_s_s (oGpgProgram, "gpg-program", "@"),
ARGPARSE_s_s (oDisplay, "display", "@"),
ARGPARSE_s_s (oTTYname, "ttyname", "@"),
ARGPARSE_s_s (oTTYtype, "ttytype", "@"),
@ -172,6 +179,14 @@ static void set_cmd (enum cmd_and_opt_values *ret_cmd,
static void emergency_cleanup (void);
/* Begin Pth wrapper functions. */
GCRY_THREAD_OPTION_PTH_IMPL;
static int fixed_gcry_pth_init (void)
{
return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
}
/* End Pth wrapper functions. */
static const char *
my_strusage( int level )
@ -299,6 +314,7 @@ main ( int argc, char **argv)
ARGPARSE_ARGS pargs;
int orig_argc;
char **orig_argv;
gpg_error_t err;
const char *fname;
int may_coredump;
FILE *configfp = NULL;
@ -324,14 +340,23 @@ main ( int argc, char **argv)
gnupg_reopen_std ("g13");
set_strusage (my_strusage);
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
gcry_control (GCRYCTL_DISABLE_INTERNAL_LOCKING);
log_set_prefix ("g13", 1);
/* Make sure that our subsystems are ready. */
i18n_init();
i18n_init ();
init_common_subsystems ();
/* Libgcrypt requires us to register the threading model first.
Note that this will also do the pth_init. */
gcry_threads_pth.init = fixed_gcry_pth_init;
err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
if (err)
{
log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
gpg_strerror (err));
}
/* Check that the Libgcrypt is suitable. */
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
@ -378,6 +403,20 @@ main ( int argc, char **argv)
Now we are now working under our real uid
*/
/* Setup malloc hooks. */
{
struct assuan_malloc_hooks malloc_hooks;
malloc_hooks.malloc = gcry_malloc;
malloc_hooks.realloc = gcry_realloc;
malloc_hooks.free = gcry_free;
assuan_set_malloc_hooks (&malloc_hooks);
}
/* Prepare libassuan. */
assuan_set_assuan_log_prefix (log_get_prefix (NULL));
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
/* Setup a default control structure for command line mode. */
memset (&ctrl, 0, sizeof ctrl);
@ -394,29 +433,31 @@ main ( int argc, char **argv)
pargs.flags = 1; /* Do not remove the args. */
next_pass:
if (configname) {
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if (parse_debug)
log_info (_("NOTE: no default option file `%s'\n"), configname);
}
else
{
log_error (_("option file `%s': %s\n"), configname, strerror(errno));
g13_exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname)
log_info (_("reading options from `%s'\n"), configname);
default_config = 0;
}
if (configname)
{
configlineno = 0;
configfp = fopen (configname, "r");
if (!configfp)
{
if (default_config)
{
if (parse_debug)
log_info (_("NOTE: no default option file `%s'\n"), configname);
}
else
{
log_error (_("option file `%s': %s\n"),
configname, strerror(errno));
g13_exit(2);
}
xfree (configname);
configname = NULL;
}
if (parse_debug && configname)
log_info (_("reading options from `%s'\n"), configname);
default_config = 0;
}
while (!no_more_options
&& optfile_parse (configfp, configname, &configlineno, &pargs, opts))
{
@ -484,6 +525,7 @@ main ( int argc, char **argv)
case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oAgentProgram: opt.agent_program = pargs.r.ret_str; break;
case oGpgProgram: opt.gpg_program = pargs.r.ret_str; break;
case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
@ -635,7 +677,10 @@ main ( int argc, char **argv)
{
if (argc != 1)
wrong_args ("--create filename");
err = create_new_container (&ctrl, argv[0]);
if (err)
log_error ("error creating a new container: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
}
break;
@ -647,8 +692,8 @@ main ( int argc, char **argv)
/* Print the audit result if needed. */
if (auditlog && auditfp)
{
audit_print_result (ctrl.audit, auditfp, 0);
audit_release (ctrl.audit);
/* audit_print_result (ctrl.audit, auditfp, 0); */
/* audit_release (ctrl.audit); */
ctrl.audit = NULL;
es_fclose (auditfp);
}
@ -686,7 +731,7 @@ g13_exit (int rc)
void
g13_init_default_ctrl (struct server_control_s *ctrl)
{
(void)ctrl;
ctrl->conttype = CONTTYPE_ENCFS;
}

View file

@ -41,7 +41,16 @@ struct
const char *homedir; /* Configuration directory name. */
const char *config_filename; /* Name of the used config file. */
/* Filename of the AGENT program. */
const char *agent_program;
/* Filename of the GPG program. Unless set via an program option it
is initialzed at the first engine startup to the standard gpg
filename. */
const char *gpg_program;
/* Environment variables passed along to the engine. */
char *display;
char *ttyname;
char *ttytype;
@ -50,7 +59,9 @@ struct
char *xauthority;
char *pinentry_user_data;
char *outfile; /* Name of the output file. */
/* Name of the output file - FIXME: what is this? */
const char *outfile;
} opt;
@ -83,6 +94,10 @@ struct server_control_s
accessed. */
int with_colons; /* Use column delimited output format */
/* Type of the current container. See the CONTTYPE_ constants. */
int conttype;
};

126
g13/keyblob.h Normal file
View file

@ -0,0 +1,126 @@
/* keyblob.h - Defs to describe a keyblob
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#ifndef G13_KEYBLOB_H
#define G13_KEYBLOB_H
/* The header block is the actual core of G13. Here is the format:
u8 Packet type. Value is 61 (0x3d).
u8 Constant value 255 (0xff).
u32 Length of the following structure
b10 Value: "GnuPG/G13\x00".
u8 Version. Value is 1.
u8 reserved
u8 reserved
u8 OS Flag: reserved, should be 0.
u32 Length of the entire header. This includes all bytes
starting at the packet type and ending with the last
padding byte of the header.
u8 Number of copies of this header (1..255).
u8 Number of copies of this header at the end of the
container (usually 0).
b6 reserved
n bytes: OpenPGP encrypted and optionally signed message.
n bytes: CMS encrypted and optionally signed packet. Such a CMS
packet will be enclosed in a a private flagged OpenPGP
packet. Either the OpenPGP encrypted packet as described
above, the CMS encrypted or both packets must exist. The
encapsulation packet has this structure:
u8 Packet type. Value is 61 (0x3d).
u8 Constant value 255 (0xff).
u32 Length of the following structure
b10 Value: "GnuPG/CMS\x00".
b(n) Regular CMS structure.
n bytes: Padding. The structure resembles an OpenPGP packet.
u8 Packet type. Value is 61 (0x3d).
u8 Constant value 255 (0xff).
u32 Length of the following structure
b10 Value: "GnuPG/PAD\x00".
b(n) Padding stuff.
Given this structure the minimum padding is 16 bytes.
n bytes: File system container.
(optionally followed by copies on the header).
*/
#define KEYBLOB_TAG_BLOBVERSION 0
/* This tag is used to describe the version of the keyblob. It must
be the first tag in a keyblob. Its value is a single byte giving
the blob version. The current version is 1. */
#define KEYBLOB_TAG_CONTTYPE 1
/* This tag gives the type of the container. The value is a two byte
big endian integer giving the type of the container as described by
the CONTTYPE_ constants. */
#define KEYBLOB_TAG_DETACHED 2
/* Indicates that the actual storage is not in the same file as the
keyblob. If a value is given it is expected to be the GUID of the
partition. */
#define KEYBLOB_TAG_KEYNO 16
/* This tag indicates a new key. The value is a 4 byte big endian
integer giving the key number. If the container type does only
need one key this key number should be 0. */
#define KEYBLOB_TAG_ENCALGO 17
/* Describes the algorithm of the key. It must follow a KEYNO tag.
The value is a 2 byte big endian algorithm number. The algorithm
numbers used are those from Libgcrypt (e.g. AES 128 is described by
the value 7). This tag is optional. */
#define KEYBLOB_TAG_ENCKEY 18
/* This tag gives the actual encryption key. It must follow a KEYNO
tag. The value is the plain key. */
#define KEYBLOB_TAG_MACALGO 19
/* Describes the MAC algorithm. It must follow a KEYNO tag. The
value is a 2 byte big endian algorithm number describing the MAC
algorithm with a value of 1 indicating HMAC. It is followed by
data specific to the MAC algorithm. In case of HMAC this data is a
2 byte big endian integer with the Libgcrypt algorithm id of the
hash algorithm. */
#define KEYBLOB_TAG_MACKEY 20
/* This tag gives the actual MACing key. It must follow a KEYNO tag.
The value is the key used for MACing. */
#define KEYBLOB_TAG_FILLER 0xffff
/* This tag may be used for alignment and padding porposes. The value
has no meaning. */
#define CONTTYPE_ENCFS 1
/* A EncFS based backend. This requires a whole directory which
includes the encrypted files. Metadata is not encrypted. */
#define CONTTYPE_TRUECRYPT 21571
/* A Truecrypt (www.truecrypt.org) based container. Due to the design
of truecrypt this requires a second datafile because it is not
possible to to prepend a truecrypt container with our keyblob. */
#endif /*G13_KEYBLOB_H*/

51
g13/utils.c Normal file
View file

@ -0,0 +1,51 @@
/* utils.c - Utility functions
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "g13.h"
#include "utils.h"
/* Append the TAG and the VALUE to the MEMBUF. There is no error
checking here; this is instead done while getting the value back
from the membuf. */
void
append_tuple (membuf_t *membuf, int tag, const void *value, size_t length)
{
unsigned char buf[2];
assert (tag >= 0 && tag <= 0xffff);
assert (length <= 0xffff);
buf[0] = tag >> 8;
buf[1] = tag;
put_membuf (membuf, buf, 2);
buf[0] = length >> 8;
buf[1] = length;
put_membuf (membuf, buf, 2);
if (length)
put_membuf (membuf, value, length);
}

32
g13/utils.h Normal file
View file

@ -0,0 +1,32 @@
/* utils.h - Defs for utility fucthe dispatcher to the various backends.ntions
* Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
*/
#ifndef G13_UTILS_H
#define G13_UTILS_H
#include "../common/membuf.h"
void append_tuple (membuf_t *membuf,
int tag, const void *value, size_t length);
#endif /*G13_UTILS_H*/