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