NeoMutt  2020-06-26-89-g172cd3
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 #include "state.h"
39 
44 {
45  short id;
46  const char *name;
47 };
48 
52 static 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 
64 static 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 
77 static void pgp_dearmor(FILE *fp_in, FILE *fp_out)
78 {
79  char line[8192];
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 (fseeko(fp_in, start, SEEK_SET) == -1)
139  {
140  mutt_debug(LL_DEBUG1, "Can't seekto start\n");
141  return;
142  }
143 
144  mutt_decode_base64(&state, end - start, false, (iconv_t) -1);
145 }
146 
153 static short pgp_mic_from_packet(unsigned char *p, size_t len)
154 {
155  /* is signature? */
156  if ((p[0] & 0x3f) != PT_SIG)
157  {
158  mutt_debug(LL_DEBUG1, "tag = %d, want %d\n", p[0] & 0x3f, PT_SIG);
159  return -1;
160  }
161 
162  if ((len >= 18) && (p[1] == 3))
163  {
164  /* version 3 signature */
165  return (short) p[17];
166  }
167  else if ((len >= 5) && (p[1] == 4))
168  {
169  /* version 4 signature */
170  return (short) p[4];
171  }
172  else
173  {
174  mutt_debug(LL_DEBUG1, "Bad signature packet\n");
175  return -1;
176  }
177 }
178 
184 static short pgp_find_hash(const char *fname)
185 {
186  size_t l;
187  short rc = -1;
188 
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  FILE *fp_in = fopen(fname, "r");
197  if (!fp_in)
198  {
199  mutt_perror(fname);
200  goto bye;
201  }
202 
203  pgp_dearmor(fp_in, fp_out);
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 
216 bye:
217 
218  mutt_file_fclose(&fp_in);
219  mutt_file_fclose(&fp_out);
221  return rc;
222 }
223 
229 const char *pgp_micalg(const char *fname)
230 {
231  return pgp_hash_to_micalg(pgp_find_hash(fname));
232 }
#define mutt_perror(...)
Definition: logging.h:85
PGP Hashing algorithm.
Definition: pgpmicalg.c:43
void pgp_release_packet(void)
Free the cached PGP packet.
Definition: pgppacket.c:239
#define _(a)
Definition: message.h:28
FILE * fp_out
File to write to.
Definition: state.h:47
Signature Packet.
Definition: pgppacket.h:39
FILE * fp_in
File to read from.
Definition: state.h:46
void mutt_decode_base64(struct State *s, size_t len, bool istext, iconv_t cd)
Decode base64-encoded text.
Definition: handler.c:1486
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:153
#define SKIPWS(ch)
Definition: string2.h:46
const char * name
Algorithm name.
Definition: pgpmicalg.c:46
#define mutt_file_mkstemp()
Definition: file.h:106
static const char * pgp_hash_to_micalg(short id)
Lookup a hash name, given its id.
Definition: pgpmicalg.c:64
bool mutt_strn_equal(const char *a, const char *b, size_t l)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:598
Keep track when processing files.
short id
Algorithm Id.
Definition: pgpmicalg.c:45
Log at debug level 1.
Definition: logging.h:40
Keep track when processing files.
Definition: state.h:44
const char * pgp_micalg(const char *fname)
Find the hash algorithm of a file.
Definition: pgpmicalg.c:229
static void pgp_dearmor(FILE *fp_in, FILE *fp_out)
Unwrap an armoured PGP block.
Definition: pgpmicalg.c:77
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
Parse PGP data packets.
int const char int line
Definition: acutest.h:617
Convenience wrapper for the library headers.
Decide how to display email content.
static short pgp_find_hash(const char *fname)
Find the hash algorithm of a file.
Definition: pgpmicalg.c:184
unsigned char * pgp_read_packet(FILE *fp, size_t *len)
Read a PGP packet from a file.
Definition: pgppacket.c:84
static short pgp_mic_from_packet(unsigned char *p, size_t len)
Get the hash algorithm from a PGP packet.
Definition: pgpmicalg.c:153
Identify the hash algorithm from a PGP signature.