]>
Commit | Line | Data |
---|---|---|
bbc27441 AJ |
1 | /* |
2 | * Copyright (C) 1996-2014 The Squid Software Foundation and contributors | |
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 CT |
17 | Ssl::CrtdMessage::CrtdMessage(MessageKind kind) |
18 | : body_size(0), state(kind == REPLY ? BEFORE_LENGTH: BEFORE_CODE) | |
95d2589c CT |
19 | {} |
20 | ||
21 | Ssl::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 | ||
118 | std::string const & Ssl::CrtdMessage::getBody() const { return body; } | |
119 | ||
120 | std::string const & Ssl::CrtdMessage::getCode() const { return code; } | |
121 | ||
122 | void Ssl::CrtdMessage::setBody(std::string const & aBody) { body = aBody; } | |
123 | ||
124 | void Ssl::CrtdMessage::setCode(std::string const & aCode) { code = aCode; } | |
125 | ||
95d2589c CT |
126 | std::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 | ||
134 | void Ssl::CrtdMessage::clear() | |
135 | { | |
136 | body_size = 0; | |
137 | state = BEFORE_CODE; | |
138 | body.clear(); | |
139 | code.clear(); | |
140 | current_block.clear(); | |
141 | } | |
142 | ||
143 | void 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 | ||
166 | void 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 | 178 | bool 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) { | |
ce394ae1 | 209 | error = "Wrong signing algoritm: " + i->second; |
06997a38 CT |
210 | return false; |
211 | } | |
87f237a9 | 212 | } else |
06997a38 CT |
213 | certProperties.signAlgorithm = Ssl::algSignTrusted; |
214 | ||
5cc307f3 | 215 | if (!Ssl::readCertAndPrivateKeyFromMemory(certProperties.signWithX509, certProperties.signWithPkey, certs_part.c_str())) { |
ce394ae1 | 216 | error = "Broken signing certificate!"; |
06997a38 CT |
217 | return false; |
218 | } | |
219 | ||
220 | static const std::string CERT_BEGIN_STR("-----BEGIN CERTIFICATE"); | |
221 | size_t pos; | |
222 | if ((pos = certs_part.find(CERT_BEGIN_STR)) != std::string::npos) { | |
223 | pos += CERT_BEGIN_STR.length(); | |
224 | if ((pos= certs_part.find(CERT_BEGIN_STR, pos)) != std::string::npos) | |
225 | Ssl::readCertFromMemory(certProperties.mimicCert, certs_part.c_str() + pos); | |
226 | } | |
227 | return true; | |
228 | } | |
229 | ||
230 | void Ssl::CrtdMessage::composeRequest(Ssl::CertificateProperties const &certProperties) | |
231 | { | |
232 | body.clear(); | |
233 | body = Ssl::CrtdMessage::param_host + "=" + certProperties.commonName; | |
234 | if (certProperties.setCommonName) | |
235 | body += "\n" + Ssl::CrtdMessage::param_SetCommonName + "=" + certProperties.commonName; | |
236 | if (certProperties.setValidAfter) | |
237 | body += "\n" + Ssl::CrtdMessage::param_SetValidAfter + "=on"; | |
238 | if (certProperties.setValidBefore) | |
239 | body += "\n" + Ssl::CrtdMessage::param_SetValidBefore + "=on"; | |
87f237a9 | 240 | if (certProperties.signAlgorithm != Ssl::algSignEnd) |
06997a38 CT |
241 | body += "\n" + Ssl::CrtdMessage::param_Sign + "=" + certSignAlgorithm(certProperties.signAlgorithm); |
242 | ||
243 | std::string certsPart; | |
1b78835c | 244 | if (!Ssl::writeCertAndPrivateKeyToMemory(certProperties.signWithX509, certProperties.signWithPkey, certsPart)) |
00fc192d | 245 | throw std::runtime_error("Ssl::writeCertAndPrivateKeyToMemory()"); |
06997a38 | 246 | if (certProperties.mimicCert.get()) { |
00fc192d AR |
247 | if (!Ssl::appendCertToMemory(certProperties.mimicCert, certsPart)) |
248 | throw std::runtime_error("Ssl::appendCertToMemory()"); | |
06997a38 CT |
249 | } |
250 | body += "\n" + certsPart; | |
251 | } | |
252 | ||
95d2589c CT |
253 | const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate"); |
254 | const std::string Ssl::CrtdMessage::param_host("host"); | |
fb2178bb CT |
255 | const std::string Ssl::CrtdMessage::param_SetValidAfter(Ssl::CertAdaptAlgorithmStr[algSetValidAfter]); |
256 | const std::string Ssl::CrtdMessage::param_SetValidBefore(Ssl::CertAdaptAlgorithmStr[algSetValidBefore]); | |
257 | const std::string Ssl::CrtdMessage::param_SetCommonName(Ssl::CertAdaptAlgorithmStr[algSetCommonName]); | |
aebe6888 | 258 | const std::string Ssl::CrtdMessage::param_Sign("Sign"); |