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