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