NeoMutt  2022-04-29-178-g3b62e6
Teaching an old dog new tricks
DOXYGEN
pgpmicalg.c
Go to the documentation of this file.
1
29#include "config.h"
30#include <iconv.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <string.h>
34#include "mutt/lib.h"
35#include "pgpmicalg.h"
36#include "handler.h"
37#include "pgppacket.h"
38
43{
44 short id;
45 const char *name;
46};
47
51static const struct HashAlgorithm HashAlgorithms[] = {
52 { 1, "pgp-md5" }, { 2, "pgp-sha1" }, { 3, "pgp-ripemd160" },
53 { 5, "pgp-md2" }, { 6, "pgp-tiger192" }, { 7, "pgp-haval-5-160" },
54 { 8, "pgp-sha256" }, { 9, "pgp-sha384" }, { 10, "pgp-sha512" },
55 { 11, "pgp-sha224" }, { -1, NULL },
56};
57
63static const char *pgp_hash_to_micalg(short id)
64{
65 for (int i = 0; HashAlgorithms[i].id >= 0; i++)
66 if (HashAlgorithms[i].id == id)
67 return HashAlgorithms[i].name;
68 return "x-unknown";
69}
70
76static void pgp_dearmor(FILE *fp_in, FILE *fp_out)
77{
78 char line[8192] = { 0 };
79 char *r = NULL;
80
81 struct State state = { 0 };
82 state.fp_in = fp_in;
83 state.fp_out = fp_out;
84
85 /* find the beginning of ASCII armor */
86
87 while ((r = fgets(line, sizeof(line), fp_in)))
88 {
89 if (mutt_strn_equal(line, "-----BEGIN", 10))
90 break;
91 }
92 if (!r)
93 {
94 mutt_debug(LL_DEBUG1, "Can't find begin of ASCII armor\n");
95 return;
96 }
97
98 /* skip the armor header */
99
100 while ((r = fgets(line, sizeof(line), fp_in)))
101 {
102 SKIPWS(r);
103 if (*r == '\0')
104 break;
105 }
106 if (!r)
107 {
108 mutt_debug(LL_DEBUG1, "Armor header doesn't end\n");
109 return;
110 }
111
112 /* actual data starts here */
113 LOFF_T start = ftello(fp_in);
114 if (start < 0)
115 return;
116
117 /* find the checksum */
118
119 while ((r = fgets(line, sizeof(line), fp_in)))
120 {
121 if ((*line == '=') || mutt_strn_equal(line, "-----END", 8))
122 break;
123 }
124 if (!r)
125 {
126 mutt_debug(LL_DEBUG1, "Can't find end of ASCII armor\n");
127 return;
128 }
129
130 LOFF_T end = ftello(fp_in) - strlen(line);
131 if (end < start)
132 {
133 mutt_debug(LL_DEBUG1, "end < start???\n");
134 return;
135 }
136
137 if (!mutt_file_seek(fp_in, start, SEEK_SET))
138 {
139 return;
140 }
141
142 mutt_decode_base64(&state, end - start, false, (iconv_t) -1);
143}
144
151static short pgp_mic_from_packet(unsigned char *p, size_t len)
152{
153 /* is signature? */
154 if ((p[0] & 0x3f) != PT_SIG)
155 {
156 mutt_debug(LL_DEBUG1, "tag = %d, want %d\n", p[0] & 0x3f, PT_SIG);
157 return -1;
158 }
159
160 if ((len >= 18) && (p[1] == 3))
161 {
162 /* version 3 signature */
163 return (short) p[17];
164 }
165 else if ((len >= 5) && (p[1] == 4))
166 {
167 /* version 4 signature */
168 return (short) p[4];
169 }
170 else
171 {
172 mutt_debug(LL_DEBUG1, "Bad signature packet\n");
173 return -1;
174 }
175}
176
182static short pgp_find_hash(const char *fname)
183{
184 size_t l;
185 short rc = -1;
186
187 FILE *fp_out = mutt_file_mkstemp();
188 if (!fp_out)
189 {
190 mutt_perror(_("Can't create temporary file"));
191 goto bye;
192 }
193
194 FILE *fp_in = fopen(fname, "r");
195 if (!fp_in)
196 {
197 mutt_perror(fname);
198 goto bye;
199 }
200
202 rewind(fp_out);
203
204 unsigned char *p = pgp_read_packet(fp_out, &l);
205 if (p)
206 {
207 rc = pgp_mic_from_packet(p, l);
208 }
209 else
210 {
211 mutt_debug(LL_DEBUG1, "No packet\n");
212 }
213
214bye:
215
219 return rc;
220}
221
227const char *pgp_micalg(const char *fname)
228{
229 return pgp_hash_to_micalg(pgp_find_hash(fname));
230}
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
#define mutt_file_mkstemp()
Definition: file.h:112
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
void mutt_decode_base64(struct State *s, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1498
Decide how to display email content.
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:473
static short pgp_mic_from_packet(unsigned char *p, size_t len)
Get the hash algorithm from a PGP packet.
Definition: pgpmicalg.c:151
static const struct HashAlgorithm HashAlgorithms[]
PGP Hashing algorithms.
Definition: pgpmicalg.c:51
static const char * pgp_hash_to_micalg(short id)
Lookup a hash name, given its id.
Definition: pgpmicalg.c:63
static short pgp_find_hash(const char *fname)
Find the hash algorithm of a file.
Definition: pgpmicalg.c:182
static void pgp_dearmor(FILE *fp_in, FILE *fp_out)
Unwrap an armoured PGP block.
Definition: pgpmicalg.c:76
const char * pgp_micalg(const char *fname)
Find the hash algorithm of a file.
Definition: pgpmicalg.c:227
Identify the hash algorithm from a PGP signature.
void pgp_release_packet(void)
Free the cached PGP packet.
Definition: pgppacket.c:240
unsigned char * pgp_read_packet(FILE *fp, size_t *len)
Read a PGP packet from a file.
Definition: pgppacket.c:85
Parse PGP data packets.
@ PT_SIG
Signature Packet.
Definition: pgppacket.h:39
#define SKIPWS(ch)
Definition: string2.h:46
PGP Hashing algorithm.
Definition: pgpmicalg.c:43
const char * name
Algorithm name.
Definition: pgpmicalg.c:45
short id
Algorithm Id.
Definition: pgpmicalg.c:44
Keep track when processing files.
Definition: state.h:46
FILE * fp_out
File to write to.
Definition: state.h:48
FILE * fp_in
File to read from.
Definition: state.h:47