crtd_message.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 
120 std::string const & Ssl::CrtdMessage::getBody() const { return body; }
121 
122 std::string const & Ssl::CrtdMessage::getCode() const { return code; }
123 
124 void Ssl::CrtdMessage::setBody(std::string const & aBody) { body = aBody; }
125 
126 void Ssl::CrtdMessage::setCode(std::string const & aCode) { code = aCode; }
127 
128 std::string Ssl::CrtdMessage::compose() const
129 {
130  if (code.empty()) return std::string();
131  char buffer[10];
132  snprintf(buffer, sizeof(buffer), "%zd", body.length());
133  return code + ' ' + buffer + ' ' + body;
134 }
135 
137 {
138  body_size = 0;
139  state = BEFORE_CODE;
140  body.clear();
141  code.clear();
142  current_block.clear();
143 }
144 
145 void Ssl::CrtdMessage::parseBody(CrtdMessage::BodyParams & map, std::string & other_part) const
146 {
147  other_part.clear();
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);
158  break;
159  } else {
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));
163  }
164  token = strtok(nullptr, "\r\n");
165  }
166 }
167 
168 void Ssl::CrtdMessage::composeBody(CrtdMessage::BodyParams const & map, std::string const & other_part)
169 {
170  body.clear();
171  for (BodyParams::const_iterator i = map.begin(); i != map.end(); ++i) {
172  if (i != map.begin())
173  body += "\n";
174  body += i->first + "=" + i->second;
175  }
176  if (!other_part.empty())
177  body += '\n' + other_part;
178 }
179 
180 void
182 {
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());
189  }
190  certProperties.commonName = i->second;
191 
193  if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
194  certProperties.setValidAfter = true;
195 
197  if (i != map.end() && strcasecmp(i->second.c_str(), "on") == 0)
198  certProperties.setValidBefore = true;
199 
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;
206  }
207 
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());
212  }
213  } else
214  certProperties.signAlgorithm = Ssl::algSignTrusted;
215 
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());
220  }
221 
222  if (!Ssl::readCertAndPrivateKeyFromMemory(certProperties.signWithX509, certProperties.signWithPkey, certs_part.c_str())) {
223  throw TextException("Broken signing certificate!", Here());
224  }
225 
226  static const std::string CERT_BEGIN_STR("-----BEGIN CERTIFICATE");
227  size_t pos;
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));
232  }
233 }
234 
236 {
237  body.clear();
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);
249 
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());
256  }
257  body += "\n" + certsPart;
258 }
259 
260 const std::string Ssl::CrtdMessage::code_new_certificate("new_certificate");
261 const std::string Ssl::CrtdMessage::param_host("host");
265 const std::string Ssl::CrtdMessage::param_Sign("Sign");
266 const std::string Ssl::CrtdMessage::param_SignHash("SignHash");
267 
static const std::string param_SetValidAfter
Parameter name for passing SetValidAfter cert adaptation variable.
Definition: crtd_message.h:80
bool appendCertToMemory(Security::CertPointer const &cert, std::string &bufferToWrite)
Definition: gadgets.cc:123
static const std::string param_host
Parameter name for passing hostname.
Definition: crtd_message.h:78
#define Here()
source code location of the caller
Definition: Here.h:15
Security::CertPointer ReadCertificate(const BIO_Pointer &)
Definition: gadgets.cc:816
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:235
Security::CertPointer signWithX509
Certificate to sign the generated request.
Definition: gadgets.h:236
const EVP_MD * signHash
The signing hash to use.
Definition: gadgets.h:243
void parseBody(BodyParams &map, std::string &other_part) const
const char * certSignAlgorithm(int sg)
Definition: gadgets.h:182
#define xisalnum(x)
Definition: xis.h:23
BIO_Pointer ReadOnlyBioTiedTo(const char *)
Definition: gadgets.cc:172
@ OK
Definition: Flag.h:16
static const std::string param_SetValidBefore
Parameter name for passing SetValidBefore cert adaptation variable.
Definition: crtd_message.h:82
void composeBody(BodyParams const &map, std::string const &other_part)
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:239
std::map< std::string, std::string > BodyParams
Definition: crtd_message.h:27
const std::string & getCode() const
Current response/request code. If parsing is not finished the method may return incompleted code.
#define xisalpha(x)
Definition: xis.h:21
static const std::string code_new_certificate
String code for "new_certificate" messages.
Definition: crtd_message.h:76
@ algSignTrusted
Definition: gadgets.h:169
@ algSignEnd
Definition: gadgets.h:169
std::string compose() const
@ algSetValidAfter
Definition: gadgets.h:207
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:239
#define xisdigit(x)
Definition: xis.h:18
@ algSetCommonName
Definition: gadgets.h:207
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition: gadgets.h:237
static const std::string param_SignHash
The signing hash to use.
Definition: crtd_message.h:88
ParseResult
Parse result codes.
Definition: crtd_message.h:29
int code
Definition: smb-errors.c:145
void setCode(std::string const &aCode)
Set new request/reply code to compose.
void composeRequest(Ssl::CertificateProperties const &)
ParseResult parse(const char *buffer, size_t len)
Definition: crtd_message.cc:23
@ algSetValidBefore
Definition: gadgets.h:207
an std::runtime_error with thrower location info
Definition: TextException.h:20
std::string commonName
A CN to use for the generated certificate.
Definition: gadgets.h:241
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
static const std::string param_Sign
Parameter name for passing signing algorithm.
Definition: crtd_message.h:86
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: gadgets.h:242
CertSignAlgorithm certSignAlgorithmId(const char *sg)
Definition: gadgets.h:194
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition: gadgets.h:238
bool writeCertAndPrivateKeyToMemory(Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey, std::string &bufferToWrite)
Definition: gadgets.cc:99
void parseRequest(CertificateProperties &)
orchestrates entire request parsing
#define xisspace(x)
Definition: xis.h:15
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition: gadgets.h:240
void clear()
Reset the class.
#define SQUID_SSL_SIGN_HASH_IF_NONE
Definition: gadgets.h:46
static const std::string param_SetCommonName
Parameter name for passing SetCommonName cert adaptation variable.
Definition: crtd_message.h:84
T * get() const
Returns raw and possibly nullptr pointer.
void setBody(std::string const &aBody)
Set new body to encode.
CrtdMessage(MessageKind kind)
Definition: crtd_message.cc:19
const std::string & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
bool readCertAndPrivateKeyFromMemory(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, char const *bufferToRead)
Definition: gadgets.cc:147

 

Introduction

Documentation

Support

Miscellaneous