aboutsummaryrefslogtreecommitdiffstats
path: root/g13
diff options
context:
space:
mode:
Diffstat (limited to 'g13')
-rw-r--r--g13/Makefile.am19
-rw-r--r--g13/backend.c83
-rw-r--r--g13/backend.h32
-rw-r--r--g13/be-encfs.c58
-rw-r--r--g13/be-encfs.h31
-rw-r--r--g13/be-truecrypt.c39
-rw-r--r--g13/be-truecrypt.h29
-rw-r--r--g13/call-gpg.c466
-rw-r--r--g13/call-gpg.h29
-rw-r--r--g13/create.c306
-rw-r--r--g13/g13.c103
-rw-r--r--g13/g13.h17
-rw-r--r--g13/keyblob.h126
-rw-r--r--g13/utils.c51
-rw-r--r--g13/utils.h32
15 files changed, 1385 insertions, 36 deletions
diff --git a/g13/Makefile.am b/g13/Makefile.am
index dce2f0b04..44f546eb7 100644
--- a/g13/Makefile.am
+++ b/g13/Makefile.am
@@ -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_LDADD = $(libcommon) ../jnlib/libjnlib.a ../gl/libgnu.a \
- $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
- $(LIBINTL)
+ 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 = $(libcommonpth) ../jnlib/libjnlib.a ../gl/libgnu.a \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_PTH_LIBS) $(PTH_LIBS) \
+ $(GPG_ERROR_LIBS) $(LIBINTL)
diff --git a/g13/backend.c b/g13/backend.c
new file mode 100644
index 000000000..a6f38719a
--- /dev/null
+++ b/g13/backend.c
@@ -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);
+ }
+}
+
diff --git a/g13/backend.h b/g13/backend.h
new file mode 100644
index 000000000..ffd03d3f5
--- /dev/null
+++ b/g13/backend.h
@@ -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*/
+
diff --git a/g13/be-encfs.c b/g13/be-encfs.c
new file mode 100644
index 000000000..18030b80e
--- /dev/null
+++ b/g13/be-encfs.c
@@ -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;
+}
+
+
diff --git a/g13/be-encfs.h b/g13/be-encfs.h
new file mode 100644
index 000000000..061385345
--- /dev/null
+++ b/g13/be-encfs.h
@@ -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*/
+
diff --git a/g13/be-truecrypt.c b/g13/be-truecrypt.c
new file mode 100644
index 000000000..6f51321f4
--- /dev/null
+++ b/g13/be-truecrypt.c
@@ -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);
+}
+
+
diff --git a/g13/be-truecrypt.h b/g13/be-truecrypt.h
new file mode 100644
index 000000000..ef2c5675b
--- /dev/null
+++ b/g13/be-truecrypt.h
@@ -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*/
+
diff --git a/g13/call-gpg.c b/g13/call-gpg.c
new file mode 100644
index 000000000..2399058b0
--- /dev/null
+++ b/g13/call-gpg.c
@@ -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 [email protected]",
+ 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;
+}
+
+
diff --git a/g13/call-gpg.h b/g13/call-gpg.h
new file mode 100644
index 000000000..3e801be3b
--- /dev/null
+++ b/g13/call-gpg.h
@@ -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*/
diff --git a/g13/create.c b/g13/create.c
new file mode 100644
index 000000000..0c6735b80
--- /dev/null
+++ b/g13/create.c
@@ -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;
+}
diff --git a/g13/g13.c b/g13/g13.c
index 85805d3aa..d6a31673d 100644
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -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;
}
diff --git a/g13/g13.h b/g13/g13.h
index ec0689a9c..5740e5860 100644
--- a/g13/g13.h
+++ b/g13/g13.h
@@ -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;
+
};
diff --git a/g13/keyblob.h b/g13/keyblob.h
new file mode 100644
index 000000000..b52919e0c
--- /dev/null
+++ b/g13/keyblob.h
@@ -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*/
diff --git a/g13/utils.c b/g13/utils.c
new file mode 100644
index 000000000..15b4426ef
--- /dev/null
+++ b/g13/utils.c
@@ -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);
+}
+
diff --git a/g13/utils.h b/g13/utils.h
new file mode 100644
index 000000000..c1104f759
--- /dev/null
+++ b/g13/utils.h
@@ -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*/
+