reorganize code a lot: create a lib-crypt with everything smime or gpg
[apps/madmutt.git] / lib-crypt / pgpmicalg.c
diff --git a/lib-crypt/pgpmicalg.c b/lib-crypt/pgpmicalg.c
new file mode 100644 (file)
index 0000000..1c322be
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright notice from original mutt:
+ * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
+
+/* This module peeks at a PGP signature and figures out the hash
+ * algorithm.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "mutt.h"
+#include "handler.h"
+#include "pgp.h"
+#include "pgppacket.h"
+#include "charset.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <lib-lib/file.h>
+
+#include <lib-mime/mime.h>
+
+#include "lib/debug.h"
+
+static struct {
+  short id;
+  const char *name;
+} HashAlgorithms[] = {
+  {
+  1, "pgp-md5"}, {
+  2, "pgp-sha1"}, {
+  3, "pgp-ripemd160"}, {
+  5, "pgp-md2"}, {
+  6, "pgp-tiger192"}, {
+  7, "pgp-haval-5-160"}, {
+  8, "pgp-sha256"}, {
+  9, "pgp-sha384"}, {
+  10, "pgp-sha512"}, {
+  -1, NULL}
+};
+
+static const char *pgp_hash_to_micalg (short id)
+{
+  int i;
+
+  for (i = 0; HashAlgorithms[i].id >= 0; i++)
+    if (HashAlgorithms[i].id == id)
+      return HashAlgorithms[i].name;
+  return "x-unknown";
+}
+
+static void pgp_dearmor (FILE * in, FILE * out)
+{
+  char line[HUGE_STRING];
+  off_t start;
+  off_t end;
+  char *r;
+
+  STATE state;
+
+  p_clear(&state, 1);
+  state.fpin = in;
+  state.fpout = out;
+
+  /* find the beginning of ASCII armor */
+
+  while ((r = fgets (line, sizeof (line), in)) != NULL) {
+    if (!strncmp (line, "-----BEGIN", 10))
+      break;
+  }
+  if (r == NULL) {
+    debug_print (1, ("Can't find begin of ASCII armor.\n"));
+    return;
+  }
+
+  /* skip the armor header */
+
+  while ((r = fgets (line, sizeof (line), in)) != NULL) {
+    r = vskipspaces(r);
+    if (!*r)
+      break;
+  }
+  if (r == NULL) {
+    debug_print (1, ("Armor header doesn't end.\n"));
+    return;
+  }
+
+  /* actual data starts here */
+  start = ftello (in);
+
+  /* find the checksum */
+
+  while ((r = fgets (line, sizeof (line), in)) != NULL) {
+    if (*line == '=' || !strncmp (line, "-----END", 8))
+      break;
+  }
+  if (r == NULL) {
+    debug_print (1, ("Can't find end of ASCII armor.\n"));
+    return;
+  }
+
+  if ((end = ftello (in) - m_strlen(line)) < start) {
+    debug_print (1, ("end < start???\n"));
+    return;
+  }
+
+  if (fseeko (in, start, SEEK_SET) == -1) {
+    debug_print (1, ("Can't seekto start.\n"));
+    return;
+  }
+
+  mutt_decode_base64 (&state, end - start, 0, (iconv_t) - 1);
+}
+
+static short pgp_mic_from_packet (unsigned char *p, size_t len)
+{
+  /* is signature? */
+  if ((p[0] & 0x3f) != PT_SIG) {
+    debug_print (1, ("tag = %d, want %d.\n", p[0] & 0x3f, PT_SIG));
+    return -1;
+  }
+
+  if (len >= 18 && p[1] == 3)
+    /* version 3 signature */
+    return (short) p[17];
+  else if (len >= 5 && p[1] == 4)
+    /* version 4 signature */
+    return (short) p[4];
+  else {
+    debug_print (1, ("Bad signature packet.\n"));
+    return -1;
+  }
+}
+
+static short pgp_find_hash (const char *fname)
+{
+  FILE *in = NULL;
+  FILE *out = NULL;
+
+  char tempfile[_POSIX_PATH_MAX];
+
+  unsigned char *p;
+  size_t l;
+
+  short rv = -1;
+
+  mutt_mktemp (tempfile);
+  if ((out = safe_fopen (tempfile, "w+")) == NULL) {
+    mutt_perror (tempfile);
+    goto bye;
+  }
+  unlink (tempfile);
+
+  if ((in = fopen (fname, "r")) == NULL) {
+    mutt_perror (fname);
+    goto bye;
+  }
+
+  pgp_dearmor (in, out);
+  rewind (out);
+
+  if ((p = pgp_read_packet (out, &l)) != NULL) {
+    rv = pgp_mic_from_packet (p, l);
+  }
+  else {
+    debug_print (1, ("No packet.\n"));
+  }
+
+bye:
+
+  safe_fclose (&in);
+  safe_fclose (&out);
+  pgp_release_packet ();
+  return rv;
+}
+
+const char *pgp_micalg (const char *fname)
+{
+  return pgp_hash_to_micalg (pgp_find_hash (fname));
+}