]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/crtd_message.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / ssl / crtd_message.cc
CommitLineData
bbc27441 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
f7f3304a 9#include "squid.h"
95d2589c 10#include "ssl/crtd_message.h"
602d9612 11#include "ssl/gadgets.h"
074d6a40 12
95d2589c 13#include <cstdlib>
95d2589c 14#include <cstring>
00fc192d 15#include <stdexcept>
95d2589c 16
ff2d7d92 17Ssl::CrtdMessage::CrtdMessage(MessageKind kind)
f53969cc 18 : body_size(0), state(kind == REPLY ? BEFORE_LENGTH: BEFORE_CODE)
95d2589c
CT
19{}
20
21Ssl::CrtdMessage::ParseResult Ssl::CrtdMessage::parse(const char * buffer, size_t len)
22{
23 char const *current_pos = buffer;
24 while (current_pos != buffer + len && state != END) {
25 switch (state) {
26 case BEFORE_CODE: {
27 if (xisspace(*current_pos)) {
d7ae3534 28 ++current_pos;
95d2589c
CT
29 break;
30 }
31 if (xisalpha(*current_pos)) {
32 state = CODE;
33 break;
34 }
35 clear();
36 return ERROR;
37 }
38 case CODE: {
39 if (xisalnum(*current_pos) || *current_pos == '_') {
40 current_block += *current_pos;
d7ae3534 41 ++current_pos;
95d2589c
CT
42 break;
43 }
44 if (xisspace(*current_pos)) {
45 code = current_block;
46 current_block.clear();
47 state = BEFORE_LENGTH;
48 break;
49 }
50 clear();
51 return ERROR;
52 }
53 case BEFORE_LENGTH: {
54 if (xisspace(*current_pos)) {
d7ae3534 55 ++current_pos;
95d2589c
CT
56 break;
57 }
58 if (xisdigit(*current_pos)) {
59 state = LENGTH;
60 break;
61 }
62 clear();
63 return ERROR;
64 }
65 case LENGTH: {
66 if (xisdigit(*current_pos)) {
67 current_block += *current_pos;
d7ae3534 68 ++current_pos;
95d2589c
CT
69 break;
70 }
71 if (xisspace(*current_pos)) {
72 body_size = atoi(current_block.c_str());
73 current_block.clear();
74 state = BEFORE_BODY;
75 break;
76 }
77 clear();
78 return ERROR;
79 }
80 case BEFORE_BODY: {
81 if (body_size == 0) {
82 state = END;
83 break;
84 }
85 if (xisspace(*current_pos)) {
d7ae3534 86 ++current_pos;
95d2589c
CT
87 break;
88 } else {
89 state = BODY;
90 break;
91 }
92 }
93 case BODY: {
94 size_t body_len = (static_cast<size_t>(buffer + len - current_pos) >= body_size - current_block.length())
95 ? body_size - current_block.length()
96 : static_cast<size_t>(buffer + len - current_pos);
97 current_block += std::string(current_pos, body_len);
98 current_pos += body_len;
99 if (current_block.length() == body_size) {
100 body = current_block;
101 state = END;
102 }
103 if (current_block.length() > body_size) {
104 clear();
105 return ERROR;
106 }
107 break;
108 }
109 case END: {
110 return OK;
111 }
112 }
113 }
114 if (state != END) return INCOMPLETE;
115 return OK;
116}
117
118std::string const & Ssl::CrtdMessage::getBody() const { return body; }
119
120std::string const & Ssl::CrtdMessage::getCode() const { return code; }
121
122void Ssl::CrtdMessage::setBody(std::string const & aBody) { body = aBody; }
123
124void Ssl::CrtdMessage::setCode(std::string const & aCode) { code = aCode; }
125
95d2589c
CT
126std::string Ssl::CrtdMessage::compose() const
127{
128 if (code.empty()) return std::string();
129 char buffer[10];
130 snprintf(buffer, sizeof(buffer), "%zd", body.length());
0af9303a 131 return code + ' ' + buffer + ' ' + body;
95d2589c
CT
132}
133
134void Ssl::CrtdMessage::clear()
135{
136 body_size = 0;
137 state = BEFORE_CODE;
138 body.clear();
139 code.clear();
140 current_block.clear();
141}
142
143void Ssl::CrtdMessage::parseBody(CrtdMessage::BodyParams & map, std::string & other_part) const
144{
145 other_part.clear();
146 // Copy string for using it as temp buffer.
147 std::string temp_body(body.c_str(), body.length());
148 char * buffer = const_cast<char *>(temp_body.c_str());
149 char * token = strtok(buffer, "\r\n");
150 while (token != NULL) {
151 std::string current_string(token);
152 size_t equal_pos = current_string.find('=');
153 if (equal_pos == std::string::npos) {
154 size_t offset_body_part = token - temp_body.c_str();
155 other_part = std::string(body.c_str() + offset_body_part, body.length() - offset_body_part);
156 break;
157 } else {
158 std::string param(current_string.c_str(), current_string.c_str() + equal_pos);
159 std::string value(current_string.c_str() + equal_pos + 1);
160 map.insert(std::make_pair(param, value));
161 }
162 token = strtok(NULL, "\r\n");
163 }
164}
165
166void Ssl::CrtdMessage::composeBody(CrtdMessage::BodyParams const & map, std::string const & other_part)
167{
168 body.clear();
d7ae3534 169 for (BodyParams::const_iterator i = map.begin(); i != map.end(); ++i) {
95d2589c
CT
170 if (i != map.begin())
171 body += "\n";
172 body += i->first + "=" + i->second;
173 }
174 if (!other_part.empty())
4e903d59 175 body += '\n' + other_part;
95d2589c
CT
176}
177
ce394ae1 178bool Ssl::CrtdMessage::parseRequest(Ssl::CertificateProperties &certProperties, std::string &error)
06997a38
CT
179{
180 Ssl::CrtdMessage::BodyParams map;
181 std::string certs_part;
182 parseBody(map, certs_part);
183 Ssl::CrtdMessage::BodyParams::iterator i = map.find(Ssl::CrtdMessage::param_host);
184 if (i == map.end()) {
ce394ae1 185 error = "Cannot find \"host\" parameter in request message";
06997a38
CT
186 return false;
187 }
188 certProperties.commonName = i->second;
87f237a9
A
189
190 i = map.find(Ssl::CrtdMessage::param_SetValidAfter);
06997a38
CT
191 if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
192 certProperties.setValidAfter = true;
87f237a9 193
06997a38
CT
194 i = map.find(Ssl::CrtdMessage::param_SetValidBefore);
195 if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
196 certProperties.setValidBefore = true;
197
198 i = map.find(Ssl::CrtdMessage::param_SetCommonName);
199 if (i != map.end()) {
87f237a9 200 // use this as Common Name instead of the hostname
06997a38
CT
201 // defined with host or Common Name from mimic cert
202 certProperties.commonName = i->second;
203 certProperties.setCommonName = true;
204 }
205
206 i = map.find(Ssl::CrtdMessage::param_Sign);
207 if (i != map.end()) {
208 if ((certProperties.signAlgorithm = Ssl::certSignAlgorithmId(i->second.c_str())) == Ssl::algSignEnd) {
3c26b00a
CT
209 error = "Wrong signing algoritm: ";
210 error += i->second;
06997a38
CT
211 return false;
212 }
87f237a9 213 } else
06997a38
CT
214 certProperties.signAlgorithm = Ssl::algSignTrusted;
215
3c26b00a
CT
216 i = map.find(Ssl::CrtdMessage::param_SignHash);
217 const char *signHashName = i != map.end() ? i->second.c_str() : SQUID_SSL_SIGN_HASH_IF_NONE;
218 if (!(certProperties.signHash = EVP_get_digestbyname(signHashName))) {
219 error = "Wrong signing hash: ";
220 error += signHashName;
221 return false;
222 }
223
5cc307f3 224 if (!Ssl::readCertAndPrivateKeyFromMemory(certProperties.signWithX509, certProperties.signWithPkey, certs_part.c_str())) {
ce394ae1 225 error = "Broken signing certificate!";
06997a38
CT
226 return false;
227 }
228
229 static const std::string CERT_BEGIN_STR("-----BEGIN CERTIFICATE");
230 size_t pos;
231 if ((pos = certs_part.find(CERT_BEGIN_STR)) != std::string::npos) {
232 pos += CERT_BEGIN_STR.length();
233 if ((pos= certs_part.find(CERT_BEGIN_STR, pos)) != std::string::npos)
234 Ssl::readCertFromMemory(certProperties.mimicCert, certs_part.c_str() + pos);
235 }
236 return true;
237}
238
239void Ssl::CrtdMessage::composeRequest(Ssl::CertificateProperties const &certProperties)
240{
241 body.clear();
242 body = Ssl::CrtdMessage::param_host + "=" + certProperties.commonName;
243 if (certProperties.setCommonName)
244 body += "\n" + Ssl::CrtdMessage::param_SetCommonName + "=" + certProperties.commonName;
245 if (certProperties.setValidAfter)
246 body += "\n" + Ssl::CrtdMessage::param_SetValidAfter + "=on";
247 if (certProperties.setValidBefore)
248 body += "\n" + Ssl::CrtdMessage::param_SetValidBefore + "=on";
87f237a9 249 if (certProperties.signAlgorithm != Ssl::algSignEnd)
06997a38 250 body += "\n" + Ssl::CrtdMessage::param_Sign + "=" + certSignAlgorithm(certProperties.signAlgorithm);
3c26b00a
CT
251 if (certProperties.signHash)
252 body += "\n" + Ssl::CrtdMessage::param_SignHash + "=" + EVP_MD_name(certProperties.signHash);
06997a38
CT
253
254 std::string certsPart;
1b78835c 255 if (!Ssl::writeCertAndPrivateKeyToMemory(certProperties.signWithX509, certProperties.signWithPkey, certsPart))
00fc192d 256 throw std::runtime_error("Ssl::writeCertAndPrivateKeyToMemory()");
06997a38 257 if (certProperties.mimicCert.get()) {
00fc192d
AR
258 if (!Ssl::appendCertToMemory(certProperties.mimicCert, certsPart))
259 throw std::runtime_error("Ssl::appendCertToMemory()");
06997a38
CT
260 }
261 body += "\n" + certsPart;
262}
263
95d2589c
CT
264const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate");
265const std::string Ssl::CrtdMessage::param_host("host");
fb2178bb
CT
266const std::string Ssl::CrtdMessage::param_SetValidAfter(Ssl::CertAdaptAlgorithmStr[algSetValidAfter]);
267const std::string Ssl::CrtdMessage::param_SetValidBefore(Ssl::CertAdaptAlgorithmStr[algSetValidBefore]);
268const std::string Ssl::CrtdMessage::param_SetCommonName(Ssl::CertAdaptAlgorithmStr[algSetCommonName]);
aebe6888 269const std::string Ssl::CrtdMessage::param_Sign("Sign");
3c26b00a 270const std::string Ssl::CrtdMessage::param_SignHash("SignHash");
f53969cc 271