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