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