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