aboutsummaryrefslogtreecommitdiffstats
path: root/sm/export.c
diff options
context:
space:
mode:
Diffstat (limited to 'sm/export.c')
-rw-r--r--sm/export.c736
1 files changed, 0 insertions, 736 deletions
diff --git a/sm/export.c b/sm/export.c
deleted file mode 100644
index 3f7457502..000000000
--- a/sm/export.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/* export.c
- * Copyright (C) 2002, 2003, 2004 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <time.h>
-#include <assert.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/wait.h>
-
-#include "gpgsm.h"
-#include <gcrypt.h>
-#include <ksba.h>
-
-#include "keydb.h"
-#include "i18n.h"
-
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-
-/* A table to store a fingerprint as used in a duplicates table. We
- don't need to hash here because a fingerprint is alrady a perfect
- hash value. This we use the most significant bits to index the
- table and then use a linked list for the overflow. Possible
- enhancement for very large number of certictates: Add a second
- level table and then resort to a linked list. */
-struct duptable_s
-{
- struct duptable_s *next;
-
- /* Note that we only need to store 19 bytes because the first byte
- is implictly given by the table index (we require at least 8
- bits). */
- unsigned char fpr[19];
-};
-typedef struct duptable_s *duptable_t;
-#define DUPTABLE_BITS 12
-#define DUPTABLE_SIZE (1 << DUPTABLE_BITS)
-
-
-static void print_short_info (ksba_cert_t cert, FILE *fp);
-static gpg_error_t export_p12 (const unsigned char *certimg, size_t certimglen,
- const char *prompt, const char *keygrip,
- FILE **retfp);
-
-
-/* Create a table used to indetify duplicated certificates. */
-static duptable_t *
-create_duptable (void)
-{
- return xtrycalloc (DUPTABLE_SIZE, sizeof (duptable_t));
-}
-
-static void
-destroy_duptable (duptable_t *table)
-{
- int idx;
- duptable_t t, t2;
-
- if (table)
- {
- for (idx=0; idx < DUPTABLE_SIZE; idx++)
- for (t = table[idx]; t; t = t2)
- {
- t2 = t->next;
- xfree (t);
- }
- xfree (table);
- }
-}
-
-/* Insert the 20 byte fingerprint FPR into TABLE. Sets EXITS to true
- if the fingerprint already exists in the table. */
-static gpg_error_t
-insert_duptable (duptable_t *table, unsigned char *fpr, int *exists)
-{
- size_t idx;
- duptable_t t;
-
- *exists = 0;
- idx = fpr[0];
-#if DUPTABLE_BITS > 16 || DUPTABLE_BITS < 8
-#error cannot handle a table larger than 16 bits or smaller than 8 bits
-#elif DUPTABLE_BITS > 8
- idx <<= (DUPTABLE_BITS - 8);
- idx |= (fpr[1] & ~(~0 << 4));
-#endif
-
- for (t = table[idx]; t; t = t->next)
- if (!memcmp (t->fpr, fpr+1, 19))
- break;
- if (t)
- {
- *exists = 1;
- return 0;
- }
- /* Insert that fingerprint. */
- t = xtrymalloc (sizeof *t);
- if (!t)
- return gpg_error_from_errno (errno);
- memcpy (t->fpr, fpr+1, 19);
- t->next = table[idx];
- table[idx] = t;
- return 0;
-}
-
-
-
-
-/* Export all certificates or just those given in NAMES. */
-void
-gpgsm_export (CTRL ctrl, STRLIST names, FILE *fp)
-{
- KEYDB_HANDLE hd = NULL;
- KEYDB_SEARCH_DESC *desc = NULL;
- int ndesc;
- Base64Context b64writer = NULL;
- ksba_writer_t writer;
- STRLIST sl;
- ksba_cert_t cert = NULL;
- int rc=0;
- int count = 0;
- int i;
- duptable_t *dtable;
-
-
- dtable = create_duptable ();
- if (!dtable)
- {
- log_error ("creating duplicates table failed: %s\n", strerror (errno));
- goto leave;
- }
-
- hd = keydb_new (0);
- if (!hd)
- {
- log_error ("keydb_new failed\n");
- goto leave;
- }
-
- if (!names)
- ndesc = 1;
- else
- {
- for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
- ;
- }
-
- desc = xtrycalloc (ndesc, sizeof *desc);
- if (!ndesc)
- {
- log_error ("allocating memory for export failed: %s\n",
- gpg_strerror (OUT_OF_CORE (errno)));
- goto leave;
- }
-
- if (!names)
- desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
- else
- {
- for (ndesc=0, sl=names; sl; sl = sl->next)
- {
- rc = keydb_classify_name (sl->d, desc+ndesc);
- if (rc)
- {
- log_error ("key `%s' not found: %s\n",
- sl->d, gpg_strerror (rc));
- rc = 0;
- }
- else
- ndesc++;
- }
- }
-
- /* If all specifications are done by fingerprint, we switch to
- ephemeral mode so that _all_ currently available and matching
- certificates are exported.
-
- fixme: we should in this case keep a list of certificates to
- avoid accidential export of duplicate certificates. */
- if (names && ndesc)
- {
- for (i=0; (i < ndesc
- && (desc[i].mode == KEYDB_SEARCH_MODE_FPR
- || desc[i].mode == KEYDB_SEARCH_MODE_FPR20
- || desc[i].mode == KEYDB_SEARCH_MODE_FPR16)); i++)
- ;
- if (i == ndesc)
- keydb_set_ephemeral (hd, 1);
- }
-
- while (!(rc = keydb_search (hd, desc, ndesc)))
- {
- unsigned char fpr[20];
- int exists;
-
- if (!names)
- desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
-
- rc = keydb_get_cert (hd, &cert);
- if (rc)
- {
- log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- gpgsm_get_fingerprint (cert, 0, fpr, NULL);
- rc = insert_duptable (dtable, fpr, &exists);
- if (rc)
- {
- log_error ("inserting into duplicates table fauiled: %s\n",
- gpg_strerror (rc));
- goto leave;
- }
-
- if (!exists && count && !ctrl->create_pem)
- {
- log_info ("exporting more than one certificate "
- "is not possible in binary mode\n");
- log_info ("ignoring other certificates\n");
- break;
- }
-
- if (!exists)
- {
- const unsigned char *image;
- size_t imagelen;
-
- image = ksba_cert_get_image (cert, &imagelen);
- if (!image)
- {
- log_error ("ksba_cert_get_image failed\n");
- goto leave;
- }
-
-
- if (ctrl->create_pem)
- {
- if (count)
- putc ('\n', fp);
- print_short_info (cert, fp);
- putc ('\n', fp);
- }
- count++;
-
- if (!b64writer)
- {
- ctrl->pem_name = "CERTIFICATE";
- rc = gpgsm_create_writer (&b64writer, ctrl, fp, &writer);
- if (rc)
- {
- log_error ("can't create writer: %s\n", gpg_strerror (rc));
- goto leave;
- }
- }
-
- rc = ksba_writer_write (writer, image, imagelen);
- if (rc)
- {
- log_error ("write error: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- if (ctrl->create_pem)
- {
- /* We want one certificate per PEM block */
- rc = gpgsm_finish_writer (b64writer);
- if (rc)
- {
- log_error ("write failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- gpgsm_destroy_writer (b64writer);
- b64writer = NULL;
- }
- }
-
- ksba_cert_release (cert);
- cert = NULL;
- }
- if (rc && rc != -1)
- log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
- else if (b64writer)
- {
- rc = gpgsm_finish_writer (b64writer);
- if (rc)
- {
- log_error ("write failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- }
-
- leave:
- gpgsm_destroy_writer (b64writer);
- ksba_cert_release (cert);
- xfree (desc);
- keydb_release (hd);
- destroy_duptable (dtable);
-}
-
-
-/* Export a certificates and its private key. */
-void
-gpgsm_p12_export (ctrl_t ctrl, const char *name, FILE *fp)
-{
- KEYDB_HANDLE hd;
- KEYDB_SEARCH_DESC *desc = NULL;
- Base64Context b64writer = NULL;
- ksba_writer_t writer;
- ksba_cert_t cert = NULL;
- int rc=0;
- const unsigned char *image;
- size_t imagelen;
- char *keygrip = NULL;
- char *prompt;
- char buffer[1024];
- int nread;
- FILE *datafp = NULL;
-
-
- hd = keydb_new (0);
- if (!hd)
- {
- log_error ("keydb_new failed\n");
- goto leave;
- }
-
- desc = xtrycalloc (1, sizeof *desc);
- if (!desc)
- {
- log_error ("allocating memory for export failed: %s\n",
- gpg_strerror (OUT_OF_CORE (errno)));
- goto leave;
- }
-
- rc = keydb_classify_name (name, desc);
- if (rc)
- {
- log_error ("key `%s' not found: %s\n",
- name, gpg_strerror (rc));
- goto leave;
- }
-
- /* Lookup the certificate an make sure that it is unique. */
- rc = keydb_search (hd, desc, 1);
- if (!rc)
- {
- rc = keydb_get_cert (hd, &cert);
- if (rc)
- {
- log_error ("keydb_get_cert failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- rc = keydb_search (hd, desc, 1);
- if (!rc)
- rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
- else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
- rc = 0;
- if (rc)
- {
- log_error ("key `%s' not found: %s\n",
- name, gpg_strerror (rc));
- goto leave;
- }
- }
-
- keygrip = gpgsm_get_keygrip_hexstring (cert);
- if (!keygrip || gpgsm_agent_havekey (ctrl, keygrip))
- {
- /* Note, that the !keygrip case indicates a bad certificate. */
- rc = gpg_error (GPG_ERR_NO_SECKEY);
- log_error ("can't export key `%s': %s\n", name, gpg_strerror (rc));
- goto leave;
- }
-
- image = ksba_cert_get_image (cert, &imagelen);
- if (!image)
- {
- log_error ("ksba_cert_get_image failed\n");
- goto leave;
- }
-
- if (ctrl->create_pem)
- {
- print_short_info (cert, fp);
- putc ('\n', fp);
- }
-
- ctrl->pem_name = "PKCS12";
- rc = gpgsm_create_writer (&b64writer, ctrl, fp, &writer);
- if (rc)
- {
- log_error ("can't create writer: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
-
- prompt = gpgsm_format_keydesc (cert);
- rc = export_p12 (image, imagelen, prompt, keygrip, &datafp);
- xfree (prompt);
- if (rc)
- goto leave;
- rewind (datafp);
- while ( (nread = fread (buffer, 1, sizeof buffer, datafp)) > 0 )
- if ((rc = ksba_writer_write (writer, buffer, nread)))
- {
- log_error ("write failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- if (ferror (datafp))
- {
- rc = gpg_error_from_errno (rc);
- log_error ("error reading temporary file: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- if (ctrl->create_pem)
- {
- /* We want one certificate per PEM block */
- rc = gpgsm_finish_writer (b64writer);
- if (rc)
- {
- log_error ("write failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- gpgsm_destroy_writer (b64writer);
- b64writer = NULL;
- }
-
- ksba_cert_release (cert);
- cert = NULL;
-
- leave:
- if (datafp)
- fclose (datafp);
- gpgsm_destroy_writer (b64writer);
- ksba_cert_release (cert);
- xfree (desc);
- keydb_release (hd);
-}
-
-
-/* Print some info about the certifciate CERT to FP */
-static void
-print_short_info (ksba_cert_t cert, FILE *fp)
-{
- char *p;
- ksba_sexp_t sexp;
- int idx;
-
- for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++)
- {
- fputs (!idx? "Issuer ...: "
- : "\n aka ...: ", fp);
- gpgsm_print_name (fp, p);
- xfree (p);
- }
- putc ('\n', fp);
-
- fputs ("Serial ...: ", fp);
- sexp = ksba_cert_get_serial (cert);
- if (sexp)
- {
- int len;
- const unsigned char *s = sexp;
-
- if (*s == '(')
- {
- s++;
- for (len=0; *s && *s != ':' && digitp (s); s++)
- len = len*10 + atoi_1 (s);
- if (*s == ':')
- for (s++; len; len--, s++)
- fprintf (fp, "%02X", *s);
- }
- xfree (sexp);
- }
- putc ('\n', fp);
-
- for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++)
- {
- fputs (!idx? "Subject ..: "
- : "\n aka ..: ", fp);
- gpgsm_print_name (fp, p);
- xfree (p);
- }
- putc ('\n', fp);
-}
-
-
-static gpg_error_t
-popen_protect_tool (const char *pgmname,
- FILE *infile, FILE *outfile, FILE **statusfile,
- const char *prompt, const char *keygrip,
- pid_t *pid)
-{
- gpg_error_t err;
- int fd, fdout, rp[2];
- int n, i;
-
- fflush (infile);
- rewind (infile);
- fd = fileno (infile);
- fdout = fileno (outfile);
- if (fd == -1 || fdout == -1)
- log_fatal ("no file descriptor for temporary file: %s\n",
- strerror (errno));
-
- /* Now start the protect-tool. */
- if (pipe (rp) == -1)
- {
- err = gpg_error_from_errno (errno);
- log_error (_("error creating a pipe: %s\n"), strerror (errno));
- return err;
- }
-
- *pid = fork ();
- if (*pid == -1)
- {
- err = gpg_error_from_errno (errno);
- log_error (_("error forking process: %s\n"), strerror (errno));
- close (rp[0]);
- close (rp[1]);
- return err;
- }
-
- if (!*pid)
- { /* Child. */
- const char *arg0;
-
- arg0 = strrchr (pgmname, '/');
- if (arg0)
- arg0++;
- else
- arg0 = pgmname;
-
- /* Connect the infile to stdin. */
- if (fd != 0 && dup2 (fd, 0) == -1)
- log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
-
- /* Connect the outfile to stdout. */
- if (fdout != 1 && dup2 (fdout, 1) == -1)
- log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
-
- /* Connect stderr to our pipe. */
- if (rp[1] != 2 && dup2 (rp[1], 2) == -1)
- log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
-
- /* Close all other files. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i=3; i < n; i++)
- close(i);
- errno = 0;
-
- setup_pinentry_env ();
-
- execlp (pgmname, arg0,
- "--homedir", opt.homedir,
- "--p12-export",
- "--prompt", prompt?prompt:"",
- "--",
- keygrip,
- NULL);
- /* No way to print anything, as we have closed all streams. */
- _exit (31);
- }
-
- /* Parent. */
- close (rp[1]);
- *statusfile = fdopen (rp[0], "r");
- if (!*statusfile)
- {
- err = gpg_error_from_errno (errno);
- log_error ("can't fdopen pipe for reading: %s", strerror (errno));
- kill (*pid, SIGTERM);
- return err;
- }
-
- return 0;
-}
-
-
-static gpg_error_t
-export_p12 (const unsigned char *certimg, size_t certimglen,
- const char *prompt, const char *keygrip,
- FILE **retfp)
-{
- const char *pgmname;
- gpg_error_t err = 0, child_err = 0;
- int i, c, cont_line;
- unsigned int pos;
- FILE *infp = NULL, *outfp = NULL, *fp = NULL;
- char buffer[1024];
- pid_t pid = -1;
-
- if (!opt.protect_tool_program || !*opt.protect_tool_program)
- pgmname = GNUPG_DEFAULT_PROTECT_TOOL;
- else
- pgmname = opt.protect_tool_program;
-
- infp = tmpfile ();
- if (!infp)
- {
- err = gpg_error_from_errno (errno);
- log_error (_("error creating temporary file: %s\n"), strerror (errno));
- goto cleanup;
- }
-
- if (fwrite (certimg, certimglen, 1, infp) != 1)
- {
- err = gpg_error_from_errno (errno);
- log_error (_("error writing to temporary file: %s\n"),
- strerror (errno));
- goto cleanup;
- }
-
- outfp = tmpfile ();
- if (!outfp)
- {
- err = gpg_error_from_errno (errno);
- log_error (_("error creating temporary file: %s\n"), strerror (errno));
- goto cleanup;
- }
-
- err = popen_protect_tool (pgmname, infp, outfp, &fp, prompt, keygrip, &pid);
- if (err)
- {
- pid = -1;
- goto cleanup;
- }
- fclose (infp);
- infp = NULL;
-
- /* Read stderr of the protect tool. */
- pos = 0;
- cont_line = 0;
- while ((c=getc (fp)) != EOF)
- {
- /* fixme: We could here grep for status information of the
- protect tool to figure out better error codes for
- CHILD_ERR. */
- buffer[pos++] = c;
- if (pos >= sizeof buffer - 5 || c == '\n')
- {
- buffer[pos - (c == '\n')] = 0;
- if (cont_line)
- log_printf ("%s", buffer);
- else
- log_info ("%s", buffer);
- pos = 0;
- cont_line = (c != '\n');
- }
- }
-
- if (pos)
- {
- buffer[pos] = 0;
- if (cont_line)
- log_printf ("%s\n", buffer);
- else
- log_info ("%s\n", buffer);
- }
- else if (cont_line)
- log_printf ("\n");
-
- /* If we found no error in the output of the child, setup a suitable
- error code, which will later be reset if the exit status of the
- child is 0. */
- if (!child_err)
- child_err = gpg_error (GPG_ERR_DECRYPT_FAILED);
-
- cleanup:
- if (infp)
- fclose (infp);
- if (fp)
- fclose (fp);
- if (pid != -1)
- {
- int status;
-
- while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
- ;
- if (i == -1)
- log_error (_("waiting for protect-tools to terminate failed: %s\n"),
- strerror (errno));
- else if (WIFEXITED (status) && WEXITSTATUS (status) == 31)
- log_error (_("error running `%s': probably not installed\n"), pgmname);
- else if (WIFEXITED (status) && WEXITSTATUS (status))
- log_error (_("error running `%s': exit status %d\n"), pgmname,
- WEXITSTATUS (status));
- else if (!WIFEXITED (status))
- log_error (_("error running `%s': terminated\n"), pgmname);
- else
- child_err = 0;
- }
- if (!err)
- err = child_err;
- if (err)
- {
- if (outfp)
- fclose (outfp);
- }
- else
- *retfp = outfp;
- return err;
-}
-