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