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