don't abort, so AFL++ doesn't count this as a crash
[ghsmtp.git] / OpenARC.cpp
blobf03ac97113e07db30c45dd909c2f381d298af51e
1 #define _Bool bool
2 #include "OpenARC.hpp"
4 #include <regex>
6 #include <stdbool.h> // needs to be above <openarc/arc.h>
8 #include <openarc/arc.h>
10 #include "iobuffer.hpp"
12 #include <fmt/format.h>
13 #include <fmt/ostream.h>
15 #include <glog/logging.h>
17 namespace {
18 u_char* uc(char const* cp)
20 return reinterpret_cast<u_char*>(const_cast<char*>(cp));
23 char const* c(u_char* ucp) { return reinterpret_cast<char const*>(ucp); }
24 } // namespace
26 OpenARC::lib::lib()
28 arc_ = arc_init();
29 CHECK_NOTNULL(arc_);
31 uint32_t arcl_flags;
32 get_option(ARC_OPTS_FLAGS, &arcl_flags, sizeof(arcl_flags));
33 arcl_flags |= ARC_LIBFLAGS_FIXCRLF;
34 set_option(ARC_OPTS_FLAGS, &arcl_flags, sizeof(arcl_flags));
36 char const* signhdrs[] = {"cc",
37 "content-language",
38 "content-transfer-encoding",
39 "content-type",
40 "date",
41 "feedback-id",
42 "from",
43 "in-reply-to",
44 "list-archive",
45 "list-help",
46 "list-id",
47 "list-owner",
48 "list-post",
49 "list-subscribe",
50 "list-unsubscribe",
51 "message-id",
52 "mime-version",
53 "precedence",
54 "references",
55 "reply-to",
56 "resent-cc",
57 "resent-date",
58 "resent-from",
59 "resent-to",
60 "subject",
61 "to",
62 nullptr};
64 set_option(ARC_OPTS_SIGNHDRS, signhdrs, sizeof(char**));
66 char const* oversignhdrs[] = {"from", nullptr};
67 set_option(ARC_OPTS_OVERSIGNHDRS, oversignhdrs, sizeof(char**));
70 OpenARC::lib::~lib()
72 set_option(ARC_OPTS_SIGNHDRS, nullptr, sizeof(char**));
73 set_option(ARC_OPTS_OVERSIGNHDRS, nullptr, sizeof(char**));
75 arc_close(arc_);
78 void OpenARC::lib::get_option(int arg, void* val, size_t valsz)
80 CHECK_EQ(arc_options(arc_, ARC_OP_GETOPT, arg, val, valsz), ARC_STAT_OK);
83 void OpenARC::lib::set_option(int arg, void* val, size_t valsz)
85 CHECK_EQ(arc_options(arc_, ARC_OP_SETOPT, arg, val, valsz), ARC_STAT_OK);
88 void OpenARC::lib::set_cv_unkn() { arc_set_cv(msg_, ARC_CHAIN_UNKNOWN); }
89 void OpenARC::lib::set_cv_none() { arc_set_cv(msg_, ARC_CHAIN_NONE); }
90 void OpenARC::lib::set_cv_fail() { arc_set_cv(msg_, ARC_CHAIN_FAIL); }
91 void OpenARC::lib::set_cv_pass() { arc_set_cv(msg_, ARC_CHAIN_PASS); }
93 void OpenARC::lib::header(std::string_view header)
95 CHECK_EQ(arc_header_field(msg_, uc(header.data()), header.length()),
96 ARC_STAT_OK);
99 void OpenARC::lib::eoh() { CHECK_EQ(arc_eoh(msg_), ARC_STAT_OK); }
101 void OpenARC::lib::body(std::string_view body)
103 CHECK_EQ(arc_body(msg_, uc(body.data()), body.length()), ARC_STAT_OK);
106 void OpenARC::lib::eom() { CHECK_EQ(arc_eom(msg_), ARC_STAT_OK); }
108 OpenARC::sign::sign()
110 u_char const* error;
111 msg_ = arc_message(arc_, ARC_CANON_RELAXED, ARC_CANON_RELAXED,
112 ARC_SIGN_RSASHA256, ARC_MODE_SIGN, &error);
113 CHECK_NOTNULL(msg_);
116 OpenARC::sign::~sign() { arc_free(msg_); }
118 bool OpenARC::sign::seal(char const* authservid,
119 char const* selector,
120 char const* domain,
121 char const* key,
122 size_t keylen,
123 char const* ar)
125 // clang-format off
126 auto const stat = arc_getseal(msg_,
127 &seal_,
128 const_cast<char*>(authservid),
129 const_cast<char*>(selector),
130 const_cast<char*>(domain),
131 uc(key),
132 keylen,
133 uc(ar));
134 // clang-format on
136 return stat == ARC_STAT_OK;
139 static std::string get_name(arc_hdrfield* hdr)
141 CHECK_NOTNULL(hdr);
142 size_t len = 0;
143 auto const p = c(arc_hdr_name(hdr, &len));
144 return std::string(p, len);
147 static std::string get_value(arc_hdrfield* hdr)
149 CHECK_NOTNULL(hdr);
150 auto const p = c(arc_hdr_value(hdr));
151 return std::string(p, strlen(p));
154 std::string OpenARC::sign::name() const { return get_name(seal_); }
156 std::string OpenARC::sign::value() const { return get_value(seal_); }
158 std::vector<std::string> OpenARC::sign::whole_seal() const
160 std::vector<std::string> hdrs;
162 auto const re = std::regex("(?:\\r\\n|\\n|\\r)");
163 for (auto sealhdr = seal_; sealhdr; sealhdr = arc_hdr_next(sealhdr)) {
164 auto const hdr =
165 fmt::format("{}:{}", get_name(sealhdr), get_value(sealhdr));
166 hdrs.emplace_back(std::regex_replace(hdr, re, "\r\n"));
169 return hdrs;
172 OpenARC::verify::verify()
174 u_char const* error;
175 msg_ = arc_message(arc_, ARC_CANON_RELAXED, ARC_CANON_RELAXED,
176 ARC_SIGN_RSASHA256, ARC_MODE_VERIFY, &error);
177 CHECK_NOTNULL(msg_);
180 OpenARC::verify::~verify() { arc_free(msg_); }
182 char const* OpenARC::verify::chain_status_str() const
184 return arc_chain_status_str(msg_);
187 std::string OpenARC::verify::chain_custody_str() const
189 for (iobuffer<char> buf{256}; buf.size() < 10 * 1024 * 1024;
190 buf.resize(buf.size() * 2)) {
191 size_t len = arc_chain_custody_str(msg_, uc(buf.data()), buf.size());
192 if (len < buf.size())
193 return std::string(buf.data(), len);
195 LOG(FATAL) << "custody chain way too large...";
196 return "";