remove a whole lot of #include mutt.h
[apps/madmutt.git] / lib-crypt / 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 #include <lib-lib/lib-lib.h>
15
16 #include <lib-mime/mime.h>
17 #include <lib-ui/curses.h>
18
19 #include "handler.h"
20 #include "pgp.h"
21 #include "pgppacket.h"
22 #include "charset.h"
23
24
25 static struct {
26   short id;
27   const char *name;
28 } HashAlgorithms[] = {
29   {
30   1, "pgp-md5"}, {
31   2, "pgp-sha1"}, {
32   3, "pgp-ripemd160"}, {
33   5, "pgp-md2"}, {
34   6, "pgp-tiger192"}, {
35   7, "pgp-haval-5-160"}, {
36   8, "pgp-sha256"}, {
37   9, "pgp-sha384"}, {
38   10, "pgp-sha512"}, {
39   -1, NULL}
40 };
41
42 static const char *pgp_hash_to_micalg (short id)
43 {
44   int i;
45
46   for (i = 0; HashAlgorithms[i].id >= 0; i++)
47     if (HashAlgorithms[i].id == id)
48       return HashAlgorithms[i].name;
49   return "x-unknown";
50 }
51
52 static void pgp_dearmor (FILE * in, FILE * out)
53 {
54   char line[HUGE_STRING];
55   off_t start;
56   off_t end;
57   char *r;
58
59   STATE state;
60
61   p_clear(&state, 1);
62   state.fpin = in;
63   state.fpout = out;
64
65   /* find the beginning of ASCII armor */
66
67   while ((r = fgets (line, sizeof (line), in)) != NULL) {
68     if (!strncmp (line, "-----BEGIN", 10))
69       break;
70   }
71   if (r == NULL) {
72     return;
73   }
74
75   /* skip the armor header */
76
77   while ((r = fgets (line, sizeof (line), in)) != NULL) {
78     r = vskipspaces(r);
79     if (!*r)
80       break;
81   }
82   if (r == NULL) {
83     return;
84   }
85
86   /* actual data starts here */
87   start = ftello (in);
88
89   /* find the checksum */
90
91   while ((r = fgets (line, sizeof (line), in)) != NULL) {
92     if (*line == '=' || !strncmp (line, "-----END", 8))
93       break;
94   }
95   if (r == NULL) {
96     return;
97   }
98
99   if ((end = ftello (in) - m_strlen(line)) < start) {
100     return;
101   }
102
103   if (fseeko (in, start, SEEK_SET) == -1) {
104     return;
105   }
106
107   mutt_decode_base64 (&state, end - start, 0, MUTT_ICONV_ERROR);
108 }
109
110 static short pgp_mic_from_packet (unsigned char *p, size_t len)
111 {
112   /* is signature? */
113   if ((p[0] & 0x3f) != PT_SIG) {
114     return -1;
115   }
116
117   if (len >= 18 && p[1] == 3)
118     /* version 3 signature */
119     return (short) p[17];
120   else if (len >= 5 && p[1] == 4)
121     /* version 4 signature */
122     return (short) p[4];
123   else {
124     return -1;
125   }
126 }
127
128 static short pgp_find_hash (const char *fname)
129 {
130   FILE *in = NULL;
131   FILE *out = NULL;
132
133   char tempfile[_POSIX_PATH_MAX];
134
135   unsigned char *p;
136   size_t l;
137
138   short rv = -1;
139
140   mutt_mktemp (tempfile);
141   if ((out = safe_fopen (tempfile, "w+")) == NULL) {
142     mutt_perror (tempfile);
143     goto bye;
144   }
145   unlink (tempfile);
146
147   if ((in = fopen (fname, "r")) == NULL) {
148     mutt_perror (fname);
149     goto bye;
150   }
151
152   pgp_dearmor (in, out);
153   rewind (out);
154
155   if ((p = pgp_read_packet (out, &l)) != NULL) {
156     rv = pgp_mic_from_packet (p, l);
157   }
158
159 bye:
160
161   safe_fclose (&in);
162   safe_fclose (&out);
163   pgp_release_packet ();
164   return rv;
165 }
166
167 const char *pgp_micalg (const char *fname)
168 {
169   return pgp_hash_to_micalg (pgp_find_hash (fname));
170 }