mutt stable branch with some hacks
1/*
2 * Copyright (C) 2001 Thomas Roessler <roessler@does-not-exist.org>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the Free
16 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301, USA.
18 */
19
20/* This module peeks at a PGP signature and figures out the hash
21 * algorithm.
22 */
23
24#if HAVE_CONFIG_H
25# include "config.h"
26#endif
27
28#include "mutt.h"
29#include "pgp.h"
30#include "pgppacket.h"
31#include "charset.h"
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <ctype.h>
37
38static const struct
39{
40 short id;
41 const char *name;
42}
43HashAlgorithms[] =
44{
45 { 1, "pgp-md5" },
46 { 2, "pgp-sha1" },
47 { 3, "pgp-ripemd160" },
48 { 5, "pgp-md2" },
49 { 6, "pgp-tiger192" },
50 { 7, "pgp-haval-5-160" },
51 { 8, "pgp-sha256" },
52 { 9, "pgp-sha384" },
53 { 10, "pgp-sha512" },
54 { 11, "pgp-sha224" },
55 { -1, NULL }
56};
57
58static const char *pgp_hash_to_micalg (short id)
59{
60 int i;
61
62 for (i = 0; HashAlgorithms[i].id >= 0; i++)
63 if (HashAlgorithms[i].id == id)
64 return HashAlgorithms[i].name;
65 return "x-unknown";
66}
67
68static void pgp_dearmor (FILE *in, FILE *out)
69{
70 char line[HUGE_STRING];
71 LOFF_T start;
72 LOFF_T end;
73 char *r;
74
75 STATE state;
76
77 memset (&state, 0, sizeof (STATE));
78 state.fpin = in;
79 state.fpout = out;
80
81 /* find the beginning of ASCII armor */
82
83 while ((r = fgets (line, sizeof (line), in)) != NULL)
84 {
85 if (!strncmp (line, "-----BEGIN", 10))
86 break;
87 }
88 if (r == NULL)
89 {
90 dprint (1, (debugfile, "pgp_dearmor: Can't find begin of ASCII armor.\n"));
91 return;
92 }
93
94 /* skip the armor header */
95
96 while ((r = fgets (line, sizeof (line), in)) != NULL)
97 {
98 SKIPWS (r);
99 if (!*r) break;
100 }
101 if (r == NULL)
102 {
103 dprint (1, (debugfile, "pgp_dearmor: Armor header doesn't end.\n"));
104 return;
105 }
106
107 /* actual data starts here */
108 start = ftello (in);
109
110 /* find the checksum */
111
112 while ((r = fgets (line, sizeof (line), in)) != NULL)
113 {
114 if (*line == '=' || !strncmp (line, "-----END", 8))
115 break;
116 }
117 if (r == NULL)
118 {
119 dprint (1, (debugfile, "pgp_dearmor: Can't find end of ASCII armor.\n"));
120 return;
121 }
122
123 if ((end = ftello (in) - strlen (line)) < start)
124 {
125 dprint (1, (debugfile, "pgp_dearmor: end < start???\n"));
126 return;
127 }
128
129 if (fseeko (in, start, SEEK_SET) == -1)
130 {
131 dprint (1, (debugfile, "pgp_dearmor: Can't seekto start.\n"));
132 return;
133 }
134
135 mutt_decode_base64 (&state, end - start, 0, (iconv_t) -1);
136}
137
138static short pgp_mic_from_packet (unsigned char *p, size_t len)
139{
140 /* is signature? */
141 if ((p[0] & 0x3f) != PT_SIG)
142 {
143 dprint (1, (debugfile, "pgp_mic_from_packet: tag = %d, want %d.\n",
144 p[0]&0x3f, PT_SIG));
145 return -1;
146 }
147
148 if (len >= 18 && p[1] == 3)
149 /* version 3 signature */
150 return (short) p[17];
151 else if (len >= 5 && p[1] == 4)
152 /* version 4 signature */
153 return (short) p[4];
154 else
155 {
156 dprint (1, (debugfile, "pgp_mic_from_packet: Bad signature packet.\n"));
157 return -1;
158 }
159}
160
161static short pgp_find_hash (const char *fname)
162{
163 FILE *in = NULL;
164 FILE *out = NULL;
165 BUFFER *tempfile = NULL;
166 unsigned char *p;
167 size_t l;
168 short rv = -1;
169
170 tempfile = mutt_buffer_pool_get ();
171 mutt_buffer_mktemp (tempfile);
172 if ((out = safe_fopen (mutt_b2s (tempfile), "w+")) == NULL)
173 {
174 mutt_perror (mutt_b2s (tempfile));
175 goto bye;
176 }
177 unlink (mutt_b2s (tempfile));
178
179 if ((in = fopen (fname, "r")) == NULL)
180 {
181 mutt_perror (fname);
182 goto bye;
183 }
184
185 pgp_dearmor (in, out);
186 rewind (out);
187
188 if ((p = pgp_read_packet (out, &l)) != NULL)
189 {
190 rv = pgp_mic_from_packet (p, l);
191 }
192 else
193 {
194 dprint (1, (debugfile, "pgp_find_hash: No packet.\n"));
195 }
196
197bye:
198 mutt_buffer_pool_release (&tempfile);
199 safe_fclose (&in);
200 safe_fclose (&out);
201 pgp_release_packet ();
202 return rv;
203}
204
205const char *pgp_micalg (const char *fname)
206{
207 return pgp_hash_to_micalg (pgp_find_hash (fname));
208}