now
[ghsmtp.git] / OpenARC.cpp
blob69634aa6b322280041427e899a658586544e3141
1 #include "OpenARC.hpp"
3 #include <regex>
5 #include <stdbool.h> // needs to be above <openarc/arc.h>
7 #include <openarc/arc.h>
9 #include "iobuffer.hpp"
11 #include <fmt/format.h>
12 #include <fmt/ostream.h>
14 #include <glog/logging.h>
16 namespace {
17 u_char* uc(char const* cp)
19 return reinterpret_cast<u_char*>(const_cast<char*>(cp));
22 char const* c(u_char* ucp) { return reinterpret_cast<char const*>(ucp); }
23 } // namespace
25 OpenARC::lib::lib()
27 arc_ = arc_init();
28 CHECK_NOTNULL(arc_);
30 uint32_t arcl_flags;
31 get_option(ARC_OPTS_FLAGS, &arcl_flags, sizeof(arcl_flags));
32 arcl_flags |= ARC_LIBFLAGS_FIXCRLF;
33 set_option(ARC_OPTS_FLAGS, &arcl_flags, sizeof(arcl_flags));
35 char const* signhdrs[] = {"cc",
36 "content-language",
37 "content-transfer-encoding",
38 "content-type",
39 "date",
40 "feedback-id",
41 "from",
42 "in-reply-to",
43 "list-archive",
44 "list-help",
45 "list-id",
46 "list-owner",
47 "list-post",
48 "list-subscribe",
49 "list-unsubscribe",
50 "message-id",
51 "mime-version",
52 "precedence",
53 "references",
54 "reply-to",
55 "resent-cc",
56 "resent-date",
57 "resent-from",
58 "resent-to",
59 "subject",
60 "to",
61 nullptr};
63 set_option(ARC_OPTS_SIGNHDRS, signhdrs, sizeof(char**));
65 char const* oversignhdrs[] = {"from", nullptr};
66 set_option(ARC_OPTS_OVERSIGNHDRS, oversignhdrs, sizeof(char**));
69 OpenARC::lib::~lib()
71 set_option(ARC_OPTS_SIGNHDRS, nullptr, sizeof(char**));
72 set_option(ARC_OPTS_OVERSIGNHDRS, nullptr, sizeof(char**));
74 arc_close(arc_);
77 void OpenARC::lib::get_option(int arg, void* val, size_t valsz)
79 CHECK_EQ(arc_options(arc_, ARC_OP_GETOPT, arg, val, valsz), ARC_STAT_OK);
82 void OpenARC::lib::set_option(int arg, void* val, size_t valsz)
84 CHECK_EQ(arc_options(arc_, ARC_OP_SETOPT, arg, val, valsz), ARC_STAT_OK);
87 void OpenARC::lib::set_cv_unkn() { arc_set_cv(msg_, ARC_CHAIN_UNKNOWN); }
88 void OpenARC::lib::set_cv_none() { arc_set_cv(msg_, ARC_CHAIN_NONE); }
89 void OpenARC::lib::set_cv_fail() { arc_set_cv(msg_, ARC_CHAIN_FAIL); }
90 void OpenARC::lib::set_cv_pass() { arc_set_cv(msg_, ARC_CHAIN_PASS); }
92 void OpenARC::lib::header(std::string_view header)
94 CHECK_EQ(arc_header_field(msg_, uc(header.data()), header.length()),
95 ARC_STAT_OK);
98 void OpenARC::lib::eoh() { CHECK_EQ(arc_eoh(msg_), ARC_STAT_OK); }
100 void OpenARC::lib::body(std::string_view body)
102 CHECK_EQ(arc_body(msg_, uc(body.data()), body.length()), ARC_STAT_OK);
105 void OpenARC::lib::eom() { CHECK_EQ(arc_eom(msg_), ARC_STAT_OK); }
107 OpenARC::sign::sign()
109 u_char const* error;
110 msg_ = arc_message(arc_, ARC_CANON_RELAXED, ARC_CANON_RELAXED,
111 ARC_SIGN_RSASHA256, ARC_MODE_SIGN, &error);
112 CHECK_NOTNULL(msg_);
115 OpenARC::sign::~sign() { arc_free(msg_); }
117 bool OpenARC::sign::seal(char const* authservid,
118 char const* selector,
119 char const* domain,
120 char const* key,
121 size_t keylen,
122 char const* ar)
124 // clang-format off
125 auto const stat = arc_getseal(msg_,
126 &seal_,
127 const_cast<char*>(authservid),
128 const_cast<char*>(selector),
129 const_cast<char*>(domain),
130 uc(key),
131 keylen,
132 uc(ar));
133 // clang-format on
135 return stat == ARC_STAT_OK;
138 static std::string get_name(arc_hdrfield* hdr)
140 CHECK_NOTNULL(hdr);
141 size_t len = 0;
142 auto const p = c(arc_hdr_name(hdr, &len));
143 return std::string(p, len);
146 static std::string get_value(arc_hdrfield* hdr)
148 CHECK_NOTNULL(hdr);
149 auto const p = c(arc_hdr_value(hdr));
150 return std::string(p, strlen(p));
153 std::string OpenARC::sign::name() const { return get_name(seal_); }
155 std::string OpenARC::sign::value() const { return get_value(seal_); }
157 std::vector<std::string> OpenARC::sign::whole_seal() const
159 std::vector<std::string> hdrs;
161 auto const re = std::regex("(?:\\r\\n|\\n|\\r)");
162 for (auto sealhdr = seal_; sealhdr; sealhdr = arc_hdr_next(sealhdr)) {
163 auto const hdr =
164 fmt::format("{}:{}", get_name(sealhdr), get_value(sealhdr));
165 hdrs.emplace_back(std::regex_replace(hdr, re, "\r\n"));
168 return hdrs;
171 OpenARC::verify::verify()
173 u_char const* error;
174 msg_ = arc_message(arc_, ARC_CANON_RELAXED, ARC_CANON_RELAXED,
175 ARC_SIGN_RSASHA256, ARC_MODE_VERIFY, &error);
176 CHECK_NOTNULL(msg_);
179 OpenARC::verify::~verify() { arc_free(msg_); }
181 char const* OpenARC::verify::chain_status_str() const
183 return arc_chain_status_str(msg_);
186 std::string OpenARC::verify::chain_custody_str() const
188 for (iobuffer<char> buf{256}; buf.size() < 10 * 1024 * 1024;
189 buf.resize(buf.size() * 2)) {
190 size_t len = arc_chain_custody_str(msg_, uc(buf.data()), buf.size());
191 if (len < buf.size())
192 return std::string(buf.data(), len);
194 LOG(FATAL) << "custody chain way too large...";
195 return "";