0caba38a2bd5de03a9b59211660f6b2b3170e281
[apps/madmutt.git] / pgpmicalg.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 /* This module peeks at a PGP signature and figures out the hash
11  * algorithm.
12  */
13
14 #if HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #include "mutt.h"
19 #include "handler.h"
20 #include "pgp.h"
21 #include "pgppacket.h"
22 #include "mime.h"
23 #include "charset.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 #include "lib/debug.h"
31
32 static struct {
33   short id;
34   const char *name;
35 } HashAlgorithms[] = {
36   {
37   1, "pgp-md5"}, {
38   2, "pgp-sha1"}, {
39   3, "pgp-ripemd160"}, {
40   5, "pgp-md2"}, {
41   6, "pgp-tiger192"}, {
42   7, "pgp-haval-5-160"}, {
43   8, "pgp-sha256"}, {
44   9, "pgp-sha384"}, {
45   10, "pgp-sha512"}, {
46   -1, NULL}
47 };
48
49 static const char *pgp_hash_to_micalg (short id)
50 {
51   int i;
52
53   for (i = 0; HashAlgorithms[i].id >= 0; i++)
54     if (HashAlgorithms[i].id == id)
55       return HashAlgorithms[i].name;
56   return "x-unknown";
57 }
58
59 static void pgp_dearmor (FILE * in, FILE * out)
60 {
61   char line[HUGE_STRING];
62   long start;
63   long end;
64   char *r;
65
66   STATE state;
67
68   memset (&state, 0, sizeof (STATE));
69   state.fpin = in;
70   state.fpout = out;
71
72   /* find the beginning of ASCII armor */
73
74   while ((r = fgets (line, sizeof (line), in)) != NULL) {
75     if (!strncmp (line, "-----BEGIN", 10))
76       break;
77   }
78   if (r == NULL) {
79     debug_print (1, ("Can't find begin of ASCII armor.\n"));
80     return;
81   }
82
83   /* skip the armor header */
84
85   while ((r = fgets (line, sizeof (line), in)) != NULL) {
86     SKIPWS (r);
87     if (!*r)
88       break;
89   }
90   if (r == NULL) {
91     debug_print (1, ("Armor header doesn't end.\n"));
92     return;
93   }
94
95   /* actual data starts here */
96   start = ftell (in);
97
98   /* find the checksum */
99
100   while ((r = fgets (line, sizeof (line), in)) != NULL) {
101     if (*line == '=' || !strncmp (line, "-----END", 8))
102       break;
103   }
104   if (r == NULL) {
105     debug_print (1, ("Can't find end of ASCII armor.\n"));
106     return;
107   }
108
109   if ((end = ftell (in) - str_len (line)) < start) {
110     debug_print (1, ("end < start???\n"));
111     return;
112   }
113
114   if (fseek (in, start, SEEK_SET) == -1) {
115     debug_print (1, ("Can't seekto start.\n"));
116     return;
117   }
118
119   mutt_decode_base64 (&state, end - start, 0, (iconv_t) - 1);
120 }
121
122 static short pgp_mic_from_packet (unsigned char *p, size_t len)
123 {
124   /* is signature? */
125   if ((p[0] & 0x3f) != PT_SIG) {
126     debug_print (1, ("tag = %d, want %d.\n", p[0] & 0x3f, PT_SIG));
127     return -1;
128   }
129
130   if (len >= 18 && p[1] == 3)
131     /* version 3 signature */
132     return (short) p[17];
133   else if (len >= 5 && p[1] == 4)
134     /* version 4 signature */
135     return (short) p[4];
136   else {
137     debug_print (1, ("Bad signature packet.\n"));
138     return -1;
139   }
140 }
141
142 static short pgp_find_hash (const char *fname)
143 {
144   FILE *in = NULL;
145   FILE *out = NULL;
146
147   char tempfile[_POSIX_PATH_MAX];
148
149   unsigned char *p;
150   size_t l;
151
152   short rv = -1;
153
154   mutt_mktemp (tempfile);
155   if ((out = safe_fopen (tempfile, "w+")) == NULL) {
156     mutt_perror (tempfile);
157     goto bye;
158   }
159   unlink (tempfile);
160
161   if ((in = fopen (fname, "r")) == NULL) {
162     mutt_perror (fname);
163     goto bye;
164   }
165
166   pgp_dearmor (in, out);
167   rewind (out);
168
169   if ((p = pgp_read_packet (out, &l)) != NULL) {
170     rv = pgp_mic_from_packet (p, l);
171   }
172   else {
173     debug_print (1, ("No packet.\n"));
174   }
175
176 bye:
177
178   safe_fclose (&in);
179   safe_fclose (&out);
180   pgp_release_packet ();
181   return rv;
182 }
183
184 const char *pgp_micalg (const char *fname)
185 {
186   return pgp_hash_to_micalg (pgp_find_hash (fname));
187 }