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