2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
10 #include "base/TextException.h"
11 #include "sbuf/Stream.h"
12 #include "ssl/crtd_message.h"
13 #include "ssl/gadgets.h"
19 Ssl::CrtdMessage::CrtdMessage(MessageKind kind
)
20 : body_size(0), state(kind
== REPLY
? BEFORE_LENGTH
: BEFORE_CODE
)
23 Ssl::CrtdMessage::ParseResult
Ssl::CrtdMessage::parse(const char * buffer
, size_t len
)
25 char const *current_pos
= buffer
;
26 while (current_pos
!= buffer
+ len
&& state
!= END
) {
29 if (xisspace(*current_pos
)) {
33 if (xisalpha(*current_pos
)) {
41 if (xisalnum(*current_pos
) || *current_pos
== '_') {
42 current_block
+= *current_pos
;
46 if (xisspace(*current_pos
)) {
48 current_block
.clear();
49 state
= BEFORE_LENGTH
;
56 if (xisspace(*current_pos
)) {
60 if (xisdigit(*current_pos
)) {
68 if (xisdigit(*current_pos
)) {
69 current_block
+= *current_pos
;
73 if (xisspace(*current_pos
)) {
74 body_size
= atoi(current_block
.c_str());
75 current_block
.clear();
87 if (xisspace(*current_pos
)) {
96 size_t body_len
= (static_cast<size_t>(buffer
+ len
- current_pos
) >= body_size
- current_block
.length())
97 ? body_size
- current_block
.length()
98 : static_cast<size_t>(buffer
+ len
- current_pos
);
99 current_block
+= std::string(current_pos
, body_len
);
100 current_pos
+= body_len
;
101 if (current_block
.length() == body_size
) {
102 body
= current_block
;
105 if (current_block
.length() > body_size
) {
116 if (state
!= END
) return INCOMPLETE
;
120 std::string
const & Ssl::CrtdMessage::getBody() const { return body
; }
122 std::string
const & Ssl::CrtdMessage::getCode() const { return code
; }
124 void Ssl::CrtdMessage::setBody(std::string
const & aBody
) { body
= aBody
; }
126 void Ssl::CrtdMessage::setCode(std::string
const & aCode
) { code
= aCode
; }
128 std::string
Ssl::CrtdMessage::compose() const
130 if (code
.empty()) return std::string();
132 snprintf(buffer
, sizeof(buffer
), "%zd", body
.length());
133 return code
+ ' ' + buffer
+ ' ' + body
;
136 void Ssl::CrtdMessage::clear()
142 current_block
.clear();
145 void Ssl::CrtdMessage::parseBody(CrtdMessage::BodyParams
& map
, std::string
& other_part
) const
148 // Copy string for using it as temp buffer.
149 std::string
temp_body(body
.c_str(), body
.length());
150 char * buffer
= const_cast<char *>(temp_body
.c_str());
151 char * token
= strtok(buffer
, "\r\n");
152 while (token
!= nullptr) {
153 std::string
current_string(token
);
154 size_t equal_pos
= current_string
.find('=');
155 if (equal_pos
== std::string::npos
) {
156 size_t offset_body_part
= token
- temp_body
.c_str();
157 other_part
= std::string(body
.c_str() + offset_body_part
, body
.length() - offset_body_part
);
160 std::string
param(current_string
.c_str(), current_string
.c_str() + equal_pos
);
161 std::string
value(current_string
.c_str() + equal_pos
+ 1);
162 map
.insert(std::make_pair(param
, value
));
164 token
= strtok(nullptr, "\r\n");
168 void Ssl::CrtdMessage::composeBody(CrtdMessage::BodyParams
const & map
, std::string
const & other_part
)
171 for (BodyParams::const_iterator i
= map
.begin(); i
!= map
.end(); ++i
) {
172 if (i
!= map
.begin())
174 body
+= i
->first
+ "=" + i
->second
;
176 if (!other_part
.empty())
177 body
+= '\n' + other_part
;
181 Ssl::CrtdMessage::parseRequest(CertificateProperties
&certProperties
)
183 Ssl::CrtdMessage::BodyParams map
;
184 std::string certs_part
;
185 parseBody(map
, certs_part
);
186 Ssl::CrtdMessage::BodyParams::iterator i
= map
.find(Ssl::CrtdMessage::param_host
);
187 if (i
== map
.end()) {
188 throw TextException("Cannot find \"host\" parameter in request message", Here());
190 certProperties
.commonName
= i
->second
;
192 i
= map
.find(Ssl::CrtdMessage::param_SetValidAfter
);
193 if (i
!= map
.end() && strcasecmp(i
->second
.c_str(), "on") == 0)
194 certProperties
.setValidAfter
= true;
196 i
= map
.find(Ssl::CrtdMessage::param_SetValidBefore
);
197 if (i
!= map
.end() && strcasecmp(i
->second
.c_str(), "on") == 0)
198 certProperties
.setValidBefore
= true;
200 i
= map
.find(Ssl::CrtdMessage::param_SetCommonName
);
201 if (i
!= map
.end()) {
202 // use this as Common Name instead of the hostname
203 // defined with host or Common Name from mimic cert
204 certProperties
.commonName
= i
->second
;
205 certProperties
.setCommonName
= true;
208 i
= map
.find(Ssl::CrtdMessage::param_Sign
);
209 if (i
!= map
.end()) {
210 if ((certProperties
.signAlgorithm
= Ssl::certSignAlgorithmId(i
->second
.c_str())) == Ssl::algSignEnd
) {
211 throw TextException(ToSBuf("Wrong signing algorithm: ", i
->second
), Here());
214 certProperties
.signAlgorithm
= Ssl::algSignTrusted
;
216 i
= map
.find(Ssl::CrtdMessage::param_SignHash
);
217 const char *signHashName
= i
!= map
.end() ? i
->second
.c_str() : SQUID_SSL_SIGN_HASH_IF_NONE
;
218 if (!(certProperties
.signHash
= EVP_get_digestbyname(signHashName
))) {
219 throw TextException(ToSBuf("Wrong signing hash: ", signHashName
), Here());
222 if (!Ssl::readCertAndPrivateKeyFromMemory(certProperties
.signWithX509
, certProperties
.signWithPkey
, certs_part
.c_str())) {
223 throw TextException("Broken signing certificate!", Here());
226 static const std::string
CERT_BEGIN_STR("-----BEGIN CERTIFICATE");
228 if ((pos
= certs_part
.find(CERT_BEGIN_STR
)) != std::string::npos
) {
229 pos
+= CERT_BEGIN_STR
.length();
230 if ((pos
= certs_part
.find(CERT_BEGIN_STR
, pos
)) != std::string::npos
)
231 certProperties
.mimicCert
= ReadCertificate(ReadOnlyBioTiedTo(certs_part
.c_str() + pos
));
235 void Ssl::CrtdMessage::composeRequest(Ssl::CertificateProperties
const &certProperties
)
238 body
= Ssl::CrtdMessage::param_host
+ "=" + certProperties
.commonName
;
239 if (certProperties
.setCommonName
)
240 body
+= "\n" + Ssl::CrtdMessage::param_SetCommonName
+ "=" + certProperties
.commonName
;
241 if (certProperties
.setValidAfter
)
242 body
+= "\n" + Ssl::CrtdMessage::param_SetValidAfter
+ "=on";
243 if (certProperties
.setValidBefore
)
244 body
+= "\n" + Ssl::CrtdMessage::param_SetValidBefore
+ "=on";
245 if (certProperties
.signAlgorithm
!= Ssl::algSignEnd
)
246 body
+= "\n" + Ssl::CrtdMessage::param_Sign
+ "=" + certSignAlgorithm(certProperties
.signAlgorithm
);
247 if (certProperties
.signHash
)
248 body
+= "\n" + Ssl::CrtdMessage::param_SignHash
+ "=" + EVP_MD_name(certProperties
.signHash
);
250 std::string certsPart
;
251 if (!Ssl::writeCertAndPrivateKeyToMemory(certProperties
.signWithX509
, certProperties
.signWithPkey
, certsPart
))
252 throw TextException("Ssl::writeCertAndPrivateKeyToMemory()", Here());
253 if (certProperties
.mimicCert
.get()) {
254 if (!Ssl::appendCertToMemory(certProperties
.mimicCert
, certsPart
))
255 throw TextException("Ssl::appendCertToMemory()", Here());
257 body
+= "\n" + certsPart
;
260 const std::string
Ssl::CrtdMessage::code_new_certificate("new_certificate");
261 const std::string
Ssl::CrtdMessage::param_host("host");
262 const std::string
Ssl::CrtdMessage::param_SetValidAfter(Ssl::CertAdaptAlgorithmStr
[algSetValidAfter
]);
263 const std::string
Ssl::CrtdMessage::param_SetValidBefore(Ssl::CertAdaptAlgorithmStr
[algSetValidBefore
]);
264 const std::string
Ssl::CrtdMessage::param_SetCommonName(Ssl::CertAdaptAlgorithmStr
[algSetCommonName
]);
265 const std::string
Ssl::CrtdMessage::param_Sign("Sign");
266 const std::string
Ssl::CrtdMessage::param_SignHash("SignHash");