Squid Web Cache master
Loading...
Searching...
No Matches
crtd_message.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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
9#include "squid.h"
10#include "base/TextException.h"
11#include "sbuf/Stream.h"
12#include "ssl/crtd_message.h"
13#include "ssl/gadgets.h"
14
15#include <cstdlib>
16#include <cstring>
17#include <stdexcept>
18
20 : body_size(0), state(kind == REPLY ? BEFORE_LENGTH: BEFORE_CODE)
21{}
22
24{
25 char const *current_pos = buffer;
26 while (current_pos != buffer + len && state != END) {
27 switch (state) {
28 case BEFORE_CODE: {
29 if (xisspace(*current_pos)) {
30 ++current_pos;
31 break;
32 }
33 if (xisalpha(*current_pos)) {
34 state = CODE;
35 break;
36 }
37 clear();
38 return ERROR;
39 }
40 case CODE: {
41 if (xisalnum(*current_pos) || *current_pos == '_') {
42 current_block += *current_pos;
43 ++current_pos;
44 break;
45 }
46 if (xisspace(*current_pos)) {
47 code = current_block;
48 current_block.clear();
49 state = BEFORE_LENGTH;
50 break;
51 }
52 clear();
53 return ERROR;
54 }
55 case BEFORE_LENGTH: {
56 if (xisspace(*current_pos)) {
57 ++current_pos;
58 break;
59 }
60 if (xisdigit(*current_pos)) {
61 state = LENGTH;
62 break;
63 }
64 clear();
65 return ERROR;
66 }
67 case LENGTH: {
68 if (xisdigit(*current_pos)) {
69 current_block += *current_pos;
70 ++current_pos;
71 break;
72 }
73 if (xisspace(*current_pos)) {
74 body_size = atoi(current_block.c_str());
75 current_block.clear();
76 state = BEFORE_BODY;
77 break;
78 }
79 clear();
80 return ERROR;
81 }
82 case BEFORE_BODY: {
83 if (body_size == 0) {
84 state = END;
85 break;
86 }
87 if (xisspace(*current_pos)) {
88 ++current_pos;
89 break;
90 } else {
91 state = BODY;
92 break;
93 }
94 }
95 case BODY: {
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;
103 state = END;
104 }
105 if (current_block.length() > body_size) {
106 clear();
107 return ERROR;
108 }
109 break;
110 }
111 case END: {
112 return OK;
113 }
114 }
115 }
116 if (state != END) return INCOMPLETE;
117 return OK;
118}
119
120std::string const & Ssl::CrtdMessage::getBody() const { return body; }
121
122std::string const & Ssl::CrtdMessage::getCode() const { return code; }
123
124void Ssl::CrtdMessage::setBody(std::string const & aBody) { body = aBody; }
125
126void Ssl::CrtdMessage::setCode(std::string const & aCode) { code = aCode; }
127
128std::string Ssl::CrtdMessage::compose() const
129{
130 if (code.empty()) return std::string();
131 return code + ' ' + std::to_string(body.length()) + ' ' + body;
132}
133
135{
136 body_size = 0;
137 state = BEFORE_CODE;
138 body.clear();
139 code.clear();
140 current_block.clear();
141}
142
143void 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 != nullptr) {
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(nullptr, "\r\n");
163 }
164}
165
166void Ssl::CrtdMessage::composeBody(CrtdMessage::BodyParams const & map, std::string const & other_part)
167{
168 body.clear();
169 for (BodyParams::const_iterator i = map.begin(); i != map.end(); ++i) {
170 if (i != map.begin())
171 body += "\n";
172 body += i->first + "=" + i->second;
173 }
174 if (!other_part.empty())
175 body += '\n' + other_part;
176}
177
178void
180{
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 throw TextException("Cannot find \"host\" parameter in request message", Here());
187 }
188 certProperties.commonName = i->second;
189
191 if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
192 certProperties.setValidAfter = true;
193
195 if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
196 certProperties.setValidBefore = true;
197
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 throw TextException(ToSBuf("Wrong signing algorithm: ", i->second), Here());
210 }
211 } else
212 certProperties.signAlgorithm = Ssl::algSignTrusted;
213
215 const char *signHashName = i != map.end() ? i->second.c_str() : SQUID_SSL_SIGN_HASH_IF_NONE;
216 if (!(certProperties.signHash = EVP_get_digestbyname(signHashName))) {
217 throw TextException(ToSBuf("Wrong signing hash: ", signHashName), Here());
218 }
219
220 if (!Ssl::readCertAndPrivateKeyFromMemory(certProperties.signWithX509, certProperties.signWithPkey, certs_part.c_str())) {
221 throw TextException("Broken signing certificate!", Here());
222 }
223
224 static const std::string CERT_BEGIN_STR("-----BEGIN CERTIFICATE");
225 size_t pos;
226 if ((pos = certs_part.find(CERT_BEGIN_STR)) != std::string::npos) {
227 pos += CERT_BEGIN_STR.length();
228 if ((pos= certs_part.find(CERT_BEGIN_STR, pos)) != std::string::npos)
229 certProperties.mimicCert = ReadCertificate(ReadOnlyBioTiedTo(certs_part.c_str() + pos));
230 }
231}
232
234{
235 body.clear();
236 body = Ssl::CrtdMessage::param_host + "=" + certProperties.commonName;
237 if (certProperties.setCommonName)
238 body += "\n" + Ssl::CrtdMessage::param_SetCommonName + "=" + certProperties.commonName;
239 if (certProperties.setValidAfter)
240 body += "\n" + Ssl::CrtdMessage::param_SetValidAfter + "=on";
241 if (certProperties.setValidBefore)
242 body += "\n" + Ssl::CrtdMessage::param_SetValidBefore + "=on";
243 if (certProperties.signAlgorithm != Ssl::algSignEnd)
244 body += "\n" + Ssl::CrtdMessage::param_Sign + "=" + certSignAlgorithm(certProperties.signAlgorithm);
245 if (certProperties.signHash)
246 body += "\n" + Ssl::CrtdMessage::param_SignHash + "=" + EVP_MD_name(certProperties.signHash);
247
248 std::string certsPart;
249 if (!Ssl::writeCertAndPrivateKeyToMemory(certProperties.signWithX509, certProperties.signWithPkey, certsPart))
250 throw TextException("Ssl::writeCertAndPrivateKeyToMemory()", Here());
251 if (certProperties.mimicCert.get()) {
252 if (!Ssl::appendCertToMemory(certProperties.mimicCert, certsPart))
253 throw TextException("Ssl::appendCertToMemory()", Here());
254 }
255 body += "\n" + certsPart;
256}
257
258const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate");
259const std::string Ssl::CrtdMessage::param_host("host");
263const std::string Ssl::CrtdMessage::param_Sign("Sign");
264const std::string Ssl::CrtdMessage::param_SignHash("SignHash");
265
#define Here()
source code location of the caller
Definition Here.h:15
T * get() const
Returns raw and possibly nullptr pointer.
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition gadgets.h:237
Security::CertPointer signWithX509
Certificate to sign the generated request.
Definition gadgets.h:236
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition gadgets.h:240
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition gadgets.h:238
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition gadgets.h:242
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition gadgets.h:239
Security::CertPointer mimicCert
Certificate to mimic.
Definition gadgets.h:235
const EVP_MD * signHash
The signing hash to use.
Definition gadgets.h:243
std::string commonName
A CN to use for the generated certificate.
Definition gadgets.h:241
void setCode(std::string const &aCode)
Set new request/reply code to compose.
static const std::string param_SetCommonName
Parameter name for passing SetCommonName cert adaptation variable.
void clear()
Reset the class.
void composeBody(BodyParams const &map, std::string const &other_part)
void setBody(std::string const &aBody)
Set new body to encode.
static const std::string param_SignHash
The signing hash to use.
static const std::string param_SetValidBefore
Parameter name for passing SetValidBefore cert adaptation variable.
static const std::string param_SetValidAfter
Parameter name for passing SetValidAfter cert adaptation variable.
static const std::string code_new_certificate
String code for "new_certificate" messages.
CrtdMessage(MessageKind kind)
std::string const & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
ParseResult
Parse result codes.
void parseBody(BodyParams &map, std::string &other_part) const
static const std::string param_host
Parameter name for passing hostname.
std::string const & getCode() const
Current response/request code. If parsing is not finished the method may return incompleted code.
ParseResult parse(const char *buffer, size_t len)
void parseRequest(CertificateProperties &)
orchestrates entire request parsing
std::map< std::string, std::string > BodyParams
static const std::string param_Sign
Parameter name for passing signing algorithm.
void composeRequest(Ssl::CertificateProperties const &)
std::string compose() const
an std::runtime_error with thrower location info
CertSignAlgorithm certSignAlgorithmId(const char *sg)
Definition gadgets.h:194
bool appendCertToMemory(Security::CertPointer const &cert, std::string &bufferToWrite)
Definition gadgets.cc:169
bool writeCertAndPrivateKeyToMemory(Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey, std::string &bufferToWrite)
Definition gadgets.cc:145
bool readCertAndPrivateKeyFromMemory(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, char const *bufferToRead)
Definition gadgets.cc:193
const char * CertAdaptAlgorithmStr[]
Definition gadgets.cc:285
const char * certSignAlgorithm(int sg)
Definition gadgets.h:182
@ algSetValidAfter
Definition gadgets.h:207
@ algSetCommonName
Definition gadgets.h:207
@ algSetValidBefore
Definition gadgets.h:207
@ algSignEnd
Definition gadgets.h:169
@ algSignTrusted
Definition gadgets.h:169
Security::CertPointer ReadCertificate(const BIO_Pointer &)
Definition gadgets.cc:862
BIO_Pointer ReadOnlyBioTiedTo(const char *)
Definition gadgets.cc:218
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition Stream.h:63
#define SQUID_SSL_SIGN_HASH_IF_NONE
Definition gadgets.h:46
#define xisspace(x)
Definition xis.h:15
#define xisalpha(x)
Definition xis.h:21
#define xisalnum(x)
Definition xis.h:23
#define xisdigit(x)
Definition xis.h:18