gadgets.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 "anyp/Host.h"
11 #include "base/IoManip.h"
12 #include "error/SysErrorDetail.h"
13 #include "ip/Address.h"
14 #include "sbuf/Stream.h"
15 #include "security/Io.h"
16 #include "ssl/gadgets.h"
17 
19 static bool
20 signWithDigest(const Security::PrivateKeyPointer &key) {
21 #if HAVE_LIBCRYPTO_EVP_PKEY_GET_DEFAULT_DIGEST_NAME
22  Assure(key); // TODO: Add and use Security::PrivateKey (here and in caller).
23  const auto pkey = key.get();
24 
25  // OpenSSL does not define a maximum name size, but does terminate longer
26  // names without returning an error to the caller. Many similar callers in
27  // OpenSSL sources use 80-byte buffers.
28  char defaultDigestName[80] = "";
29  const auto nameGetterResult = EVP_PKEY_get_default_digest_name(pkey, defaultDigestName, sizeof(defaultDigestName));
30  debugs(83, 3, "nameGetterResult=" << nameGetterResult << " defaultDigestName=" << defaultDigestName);
31  if (nameGetterResult <= 0) {
32  debugs(83, 3, "ERROR: EVP_PKEY_get_default_digest_name() failure: " << Ssl::ReportAndForgetErrors);
33  // Backward compatibility: On error, assume digest should be used.
34  // TODO: Return false for -2 nameGetterResult as it "indicates the
35  // operation is not supported by the public key algorithm"?
36  return true;
37  }
38 
39  // The name "UNDEF" signifies that a digest must (for return value 2) or may
40  // (for return value 1) be left unspecified.
41  if (nameGetterResult == 2 && strcmp(defaultDigestName, "UNDEF") == 0)
42  return false;
43 
44  // Defined mandatory algorithms and "may be left unspecified" cases mentioned above.
45  return true;
46 
47 #else
48  // TODO: Drop this legacy code when we stop supporting OpenSSL v1;
49  // EVP_PKEY_get_default_digest_name() is available starting with OpenSSL v3.
50  (void)key;
51 
52  // assume that digest is required for all key types supported by older OpenSSL versions
53  return true;
54 #endif // HAVE_LIBCRYPTO_EVP_PKEY_GET_DEFAULT_DIGEST_NAME
55 }
56 
58 static auto
59 Sign(Security::Certificate &cert, const Security::PrivateKeyPointer &key, const EVP_MD &availableDigest) {
60  const auto digestOrNil = signWithDigest(key) ? &availableDigest : nullptr;
61  return X509_sign(&cert, key.get(), digestOrNil);
62 }
63 
64 void
66 {
67  if (ERR_peek_last_error()) {
68  debugs(83, 5, "forgetting stale OpenSSL errors:" << ReportAndForgetErrors);
69  // forget errors if section/level-specific debugging above was disabled
70  while (ERR_get_error()) {}
71  }
72 
73  // Technically, the caller should just ignore (potentially stale) errno when
74  // no system calls have failed. However, due to OpenSSL error-reporting API
75  // deficiencies, many callers cannot detect when a TLS error was caused by a
76  // system call failure. We forget the stale errno (just like we forget stale
77  // OpenSSL errors above) so that the caller only uses fresh errno values.
78  errno = 0;
79 }
80 
81 std::ostream &
82 Ssl::ReportAndForgetErrors(std::ostream &os)
83 {
84  unsigned int reported = 0; // efficiently marks ForgetErrors() call boundary
85  while (const auto errorToForget = ERR_get_error())
86  os << Debug::Extra << "OpenSSL-saved error #" << (++reported) << ": 0x" << asHex(errorToForget);
87  return os;
88 }
89 
90 [[ noreturn ]] static void
91 ThrowErrors(const char * const problem, const int savedErrno, const SourceLocation &where)
92 {
93  throw TextException(ToSBuf(problem, ": ",
95  ReportSysError(savedErrno)),
96  where);
97 }
98 
99 static Security::PrivateKeyPointer
101 {
102  Ssl::EVP_PKEY_CTX_Pointer rsa(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, nullptr));
103  if (!rsa)
104  return nullptr;
105 
106  if (EVP_PKEY_keygen_init(rsa.get()) <= 0)
107  return nullptr;
108 
109  int num = 2048; // Maybe use 4096 RSA keys, or better make it configurable?
110  if (EVP_PKEY_CTX_set_rsa_keygen_bits(rsa.get(), num) <= 0)
111  return nullptr;
112 
113  /* Generate key */
114  EVP_PKEY *pkey = nullptr;
115  if (EVP_PKEY_keygen(rsa.get(), &pkey) <= 0)
116  return nullptr;
117 
118  return Security::PrivateKeyPointer(pkey);
119 }
120 
125 static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
126 {
127  if (!ai)
128  return false;
129  Ssl::BIGNUM_Pointer bn(BN_new());
130  if (serial) {
131  bn.reset(BN_dup(serial));
132  } else {
133  if (!bn)
134  return false;
135 
136  if (!BN_rand(bn.get(), 64, 0, 0))
137  return false;
138  }
139 
140  if (ai && !BN_to_ASN1_INTEGER(bn.get(), ai))
141  return false;
142  return true;
143 }
144 
145 bool Ssl::writeCertAndPrivateKeyToMemory(Security::CertPointer const & cert, Security::PrivateKeyPointer const & pkey, std::string & bufferToWrite)
146 {
147  bufferToWrite.clear();
148  if (!pkey || !cert)
149  return false;
150  BIO_Pointer bio(BIO_new(BIO_s_mem()));
151  if (!bio)
152  return false;
153 
154  if (!PEM_write_bio_X509 (bio.get(), cert.get()))
155  return false;
156 
157  if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr))
158  return false;
159 
160  char *ptr = nullptr;
161  long len = BIO_get_mem_data(bio.get(), &ptr);
162  if (!ptr)
163  return false;
164 
165  bufferToWrite = std::string(ptr, len);
166  return true;
167 }
168 
169 bool Ssl::appendCertToMemory(Security::CertPointer const & cert, std::string & bufferToWrite)
170 {
171  if (!cert)
172  return false;
173 
174  BIO_Pointer bio(BIO_new(BIO_s_mem()));
175  if (!bio)
176  return false;
177 
178  if (!PEM_write_bio_X509 (bio.get(), cert.get()))
179  return false;
180 
181  char *ptr = nullptr;
182  long len = BIO_get_mem_data(bio.get(), &ptr);
183  if (!ptr)
184  return false;
185 
186  if (!bufferToWrite.empty())
187  bufferToWrite.append(" "); // add a space...
188 
189  bufferToWrite.append(ptr, len);
190  return true;
191 }
192 
193 bool Ssl::readCertAndPrivateKeyFromMemory(Security::CertPointer & cert, Security::PrivateKeyPointer & pkey, char const * bufferToRead)
194 {
195  Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
196  BIO_puts(bio.get(), bufferToRead);
197 
198  try {
199  cert = ReadCertificate(bio);
200  } catch (...) {
201  debugs(83, DBG_IMPORTANT, "ERROR: Cannot deserialize a signing certificate:" <<
202  Debug::Extra << "problem: " << CurrentException);
203  cert.reset();
204  pkey.reset();
205  return false;
206  }
207 
208  EVP_PKEY * pkeyPtr = nullptr;
209  pkey.resetWithoutLocking(PEM_read_bio_PrivateKey(bio.get(), &pkeyPtr, nullptr, nullptr));
210  if (!pkey)
211  return false;
212 
213  return true;
214 }
215 
216 // TODO: Convert matching BIO_s_mem() callers.
218 Ssl::ReadOnlyBioTiedTo(const char * const bufferToRead)
219 {
220  ForgetErrors();
221  // OpenSSL BIO API is not const-correct, but OpenSSL does not free or modify
222  // BIO_new_mem_buf() data because it is marked with BIO_FLAGS_MEM_RDONLY.
223  const auto castedBuffer = const_cast<char*>(bufferToRead);
224  if (const auto bio = BIO_new_mem_buf(castedBuffer, -1)) // no memcpy()
225  return BIO_Pointer(bio);
226  const auto savedErrno = errno;
227  ThrowErrors("cannot allocate OpenSSL BIO structure", savedErrno, Here());
228 }
229 
230 // According to RFC 5280 (Section A.1), the common name length in a certificate
231 // can be at most 64 characters
232 static const size_t MaxCnLen = 64;
233 
234 // Replace certs common name with the given
235 static bool replaceCommonName(Security::CertPointer & cert, std::string const &rawCn)
236 {
237  std::string cn = rawCn;
238 
239  if (cn.length() > MaxCnLen) {
240  // In the case the length of CN is more than the maximum supported size
241  // try to use the first upper level domain.
242  size_t pos = 0;
243  do {
244  pos = cn.find('.', pos + 1);
245  } while (pos != std::string::npos && (cn.length() - pos + 2) > MaxCnLen);
246 
247  // If no short domain found or this domain is a toplevel domain
248  // we failed to find a good cn name.
249  if (pos == std::string::npos || cn.find('.', pos + 1) == std::string::npos)
250  return false;
251 
252  std::string fixedCn(1, '*');
253  fixedCn.append(cn.c_str() + pos);
254  cn = fixedCn;
255  }
256 
257  // Assume [] surround an IPv6 address and strip them because browsers such
258  // as Firefox, Chromium, and Safari prefer bare IPv6 addresses in CNs.
259  if (cn.length() > 2 && *cn.begin() == '[' && *cn.rbegin() == ']')
260  cn = cn.substr(1, cn.size()-2);
261 
262  X509_NAME *name = X509_get_subject_name(cert.get());
263  if (!name)
264  return false;
265  // Remove the CN part:
266  int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
267  if (loc >=0) {
268  X509_NAME_ENTRY *tmp = X509_NAME_get_entry(name, loc);
269  X509_NAME_delete_entry(name, loc);
270  X509_NAME_ENTRY_free(tmp);
271  }
272 
273  // Add a new CN
274  return X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
275  (unsigned char *)(cn.c_str()), -1, -1, 0);
276 }
277 
278 const char *Ssl::CertSignAlgorithmStr[] = {
279  "signTrusted",
280  "signUntrusted",
281  "signSelf",
282  nullptr
283 };
284 
285 const char *Ssl::CertAdaptAlgorithmStr[] = {
286  "setValidAfter",
287  "setValidBefore",
288  "setCommonName",
289  nullptr
290 };
291 
293  setValidAfter(false),
294  setValidBefore(false),
295  setCommonName(false),
296  signAlgorithm(Ssl::algSignEnd),
297  signHash(nullptr)
298 {}
299 
300 static void
301 printX509Signature(const Security::CertPointer &cert, std::string &out)
302 {
303  const ASN1_BIT_STRING *sig = Ssl::X509_get_signature(cert);
304  if (sig && sig->data) {
305  const unsigned char *s = sig->data;
306  for (int i = 0; i < sig->length; ++i) {
307  char hex[3];
308  snprintf(hex, sizeof(hex), "%02x", s[i]);
309  out.append(hex);
310  }
311  }
312 }
313 
314 std::string &
316 {
317  static std::string certKey;
318  certKey.clear();
319  certKey.reserve(4096);
320  if (properties.mimicCert.get())
321  printX509Signature(properties.mimicCert, certKey);
322 
323  if (certKey.empty()) {
324  certKey.append("/CN=", 4);
325  certKey.append(properties.commonName);
326  }
327 
328  if (properties.setValidAfter)
329  certKey.append("+SetValidAfter=on", 17);
330 
331  if (properties.setValidBefore)
332  certKey.append("+SetValidBefore=on", 18);
333 
334  if (properties.setCommonName) {
335  certKey.append("+SetCommonName=", 15);
336  certKey.append(properties.commonName);
337  }
338 
339  if (properties.signAlgorithm != Ssl::algSignEnd) {
340  certKey.append("+Sign=", 6);
341  certKey.append(certSignAlgorithm(properties.signAlgorithm));
342  }
343 
344  if (properties.signHash != nullptr) {
345  certKey.append("+SignHash=", 10);
346  certKey.append(EVP_MD_name(properties.signHash));
347  }
348 
349  return certKey;
350 }
351 
358 static bool
360 {
361  if (!mimicCert.get() || !issuerCert.get())
362  return false;
363 
364  Ssl::AUTHORITY_KEYID_Pointer akid((AUTHORITY_KEYID *)X509_get_ext_d2i(mimicCert.get(), NID_authority_key_identifier, nullptr, nullptr));
365 
366  bool addKeyId = false, addIssuer = false;
367  if (akid.get()) {
368  addKeyId = (akid.get()->keyid != nullptr);
369  addIssuer = (akid.get()->issuer && akid.get()->serial);
370  }
371 
372  if (!addKeyId && !addIssuer)
373  return false; // No need to add AuthorityKeyIdentifier
374 
375  Ssl::ASN1_OCTET_STRING_Pointer issuerKeyId;
376  if (addKeyId) {
377  X509_EXTENSION *ext;
378  // Check if the issuer has the Subject Key Identifier extension
379  const int index = X509_get_ext_by_NID(issuerCert.get(), NID_subject_key_identifier, -1);
380  if (index >= 0 && (ext = X509_get_ext(issuerCert.get(), index))) {
381  issuerKeyId.reset((ASN1_OCTET_STRING *)X509V3_EXT_d2i(ext));
382  }
383  }
384 
385  Ssl::X509_NAME_Pointer issuerName;
386  Ssl::ASN1_INT_Pointer issuerSerial;
387  if (issuerKeyId.get() == nullptr || addIssuer) {
388  issuerName.reset(X509_NAME_dup(X509_get_issuer_name(issuerCert.get())));
389  issuerSerial.reset(ASN1_INTEGER_dup(X509_get_serialNumber(issuerCert.get())));
390  }
391 
392  Ssl::AUTHORITY_KEYID_Pointer theAuthKeyId(AUTHORITY_KEYID_new());
393  if (!theAuthKeyId.get())
394  return false;
395  theAuthKeyId.get()->keyid = issuerKeyId.release();
396  if (issuerName && issuerSerial) {
397  Ssl::GENERAL_NAME_STACK_Pointer genNames(sk_GENERAL_NAME_new_null());
398  if (genNames.get()) {
399  if (GENERAL_NAME *aname = GENERAL_NAME_new()) {
400  sk_GENERAL_NAME_push(genNames.get(), aname);
401  aname->type = GEN_DIRNAME;
402  aname->d.dirn = issuerName.release();
403  theAuthKeyId.get()->issuer = genNames.release();
404  theAuthKeyId.get()->serial = issuerSerial.release();
405  }
406  }
407  }
408 
409  // The Authority Key Identifier extension should include KeyId or/and both
411  if (!theAuthKeyId.get()->keyid && (!theAuthKeyId.get()->issuer || !theAuthKeyId.get()->serial))
412  return false;
413 
414  const X509V3_EXT_METHOD *method = X509V3_EXT_get_nid(NID_authority_key_identifier);
415  if (!method)
416  return false;
417 
418  unsigned char *ext_der = nullptr;
419  int ext_len = ASN1_item_i2d((ASN1_VALUE *)theAuthKeyId.get(), &ext_der, ASN1_ITEM_ptr(method->it));
420  Ssl::ASN1_OCTET_STRING_Pointer extOct(ASN1_OCTET_STRING_new());
421  extOct.get()->data = ext_der;
422  extOct.get()->length = ext_len;
423  Ssl::X509_EXTENSION_Pointer extAuthKeyId(X509_EXTENSION_create_by_NID(nullptr, NID_authority_key_identifier, 0, extOct.get()));
424  if (!extAuthKeyId.get())
425  return false;
426 
427  if (!X509_add_ext(cert.get(), extAuthKeyId.get(), -1))
428  return false;
429 
430  return true;
431 }
432 
435 // Currently only extensions which are reported by the users that required are
436 // mimicked. More safe to mimic extensions would be added here if users request
437 // them.
438 static int
440 {
441  static int extensions[]= {
442  NID_key_usage,
443  NID_ext_key_usage,
444  NID_basic_constraints,
445  0
446  };
447 
448  // key usage bit names
449  enum {
450  DigitalSignature,
451  NonRepudiation,
452  KeyEncipherment, // NSS requires for RSA but not EC
453  DataEncipherment,
454  KeyAgreement,
455  KeyCertificateSign,
456  CRLSign,
457  EncipherOnly,
458  DecipherOnly
459  };
460 
461  // XXX: Add PublicKeyPointer. In OpenSSL, public and private keys are
462  // internally represented by EVP_PKEY pair, but GnuTLS uses distinct types.
463  const Security::PrivateKeyPointer certKey(X509_get_pubkey(mimicCert.get()));
464 #if OPENSSL_VERSION_MAJOR < 3
465  const auto rsaPkey = EVP_PKEY_get0_RSA(certKey.get()) != nullptr;
466 #else
467  const auto rsaPkey = EVP_PKEY_is_a(certKey.get(), "RSA") == 1;
468 #endif
469 
470  int added = 0;
471  int nid;
472  for (int i = 0; (nid = extensions[i]) != 0; ++i) {
473  const int pos = X509_get_ext_by_NID(mimicCert.get(), nid, -1);
474  if (X509_EXTENSION *ext = X509_get_ext(mimicCert.get(), pos)) {
475  // Mimic extension exactly.
476  if (X509_add_ext(cert.get(), ext, -1))
477  ++added;
478  if (nid == NID_key_usage && !rsaPkey) {
479  // NSS does not require the KeyEncipherment flag on EC keys
480  // but it does require it for RSA keys. Since ssl-bump
481  // substitutes RSA keys for EC ones, we need to ensure that
482  // that the more stringent requirements are met.
483 
484  const int p = X509_get_ext_by_NID(cert.get(), NID_key_usage, -1);
485  if ((ext = X509_get_ext(cert.get(), p)) != nullptr) {
486  ASN1_BIT_STRING *keyusage = (ASN1_BIT_STRING *)X509V3_EXT_d2i(ext);
487  ASN1_BIT_STRING_set_bit(keyusage, KeyEncipherment, 1);
488 
489  //Build the ASN1_OCTET_STRING
490  const X509V3_EXT_METHOD *method = X509V3_EXT_get(ext);
491  assert(method && method->it);
492  unsigned char *ext_der = nullptr;
493  int ext_len = ASN1_item_i2d((ASN1_VALUE *)keyusage,
494  &ext_der,
495  (const ASN1_ITEM *)ASN1_ITEM_ptr(method->it));
496 
497  ASN1_OCTET_STRING *ext_oct = ASN1_OCTET_STRING_new();
498  ext_oct->data = ext_der;
499  ext_oct->length = ext_len;
500  X509_EXTENSION_set_data(ext, ext_oct);
501 
502  ASN1_OCTET_STRING_free(ext_oct);
503  ASN1_BIT_STRING_free(keyusage);
504  }
505  }
506  }
507  }
508 
509  if (mimicAuthorityKeyId(cert, mimicCert, issuerCert))
510  ++added;
511 
512  // We could also restrict mimicking of the CA extension to CA:FALSE
513  // because Squid does not generate valid fake CA certificates.
514 
515  return added;
516 }
517 
518 SBuf
519 Ssl::AsnToSBuf(const ASN1_STRING &buffer)
520 {
521  return SBuf(reinterpret_cast<const char *>(buffer.data), buffer.length);
522 }
523 
525 static std::optional<SBuf>
526 ParseAsUtf8(const ASN1_STRING &asnBuffer)
527 {
528  unsigned char *utfBuffer = nullptr;
529  const auto conversionResult = ASN1_STRING_to_UTF8(&utfBuffer, &asnBuffer);
530  if (conversionResult < 0) {
531  debugs(83, 3, "failed" << Ssl::ReportAndForgetErrors);
532  return std::nullopt;
533  }
534  Assure(utfBuffer);
535  const auto utfChars = reinterpret_cast<char *>(utfBuffer);
536  const auto utfLength = static_cast<size_t>(conversionResult);
537  Ssl::UniqueCString bufferDestroyer(utfChars);
538  return SBuf(utfChars, utfLength);
539 }
540 
541 std::optional<AnyP::Host>
543 {
544  if (const auto ip = Ip::Address::Parse(SBuf(text).c_str()))
545  return AnyP::Host::ParseIp(*ip);
547 }
548 
549 std::optional<AnyP::Host>
550 Ssl::ParseCommonNameAt(X509_NAME &name, const int cnIndex)
551 {
552  const auto cn = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(&name, cnIndex));
553  if (!cn) {
554  debugs(83, 7, "no CN at " << cnIndex);
555  return std::nullopt;
556  }
557 
558  // CN buffer usually contains an ASCII domain name, but X.509 and TLS allow
559  // other name encodings (e.g., UTF-16), and some CNs are not domain names
560  // (e.g., organization name or perhaps even a dotted IP address). We do our
561  // best to identify IP addresses and treat anything else as a domain name.
562  // TODO: Do not treat CNs with spaces or without periods as domain names.
563 
564  // OpenSSL does not offer ASN1_STRING_to_ASCII(), so we convert to UTF-8
565  // that usually "works" for further parsing/validation/comparison purposes
566  // even though Squid code will treat multi-byte characters as char bytes.
567  // TODO: Confirm that OpenSSL preserves UTF-8 when we add a "DNS:..." SAN.
568 
569  if (const auto utf = ParseAsUtf8(*cn))
570  return ParseAsSimpleDomainNameOrIp(*utf);
571  return std::nullopt;
572 }
573 
576 static bool
578 {
579  X509_NAME *name = X509_get_subject_name(cert.get());
580  if (!name)
581  return false;
582 
583  const int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
584  if (loc < 0)
585  return false;
586 
587  const auto cn = Ssl::ParseCommonNameAt(*name, loc);
588  if (!cn)
589  return false;
590 
591  // We create an "IP:address" or "DNS:name" text that X509V3_EXT_conf_nid()
592  // then parses and converts to OpenSSL GEN_IPADD or GEN_DNS GENERAL_NAME.
593  // TODO: Use X509_add1_ext_i2d() to add a GENERAL_NAME extension directly:
594  // https://github.com/openssl/openssl/issues/11706#issuecomment-633180151
595  const auto altNamePrefix = cn->ip() ? "IP:" : "DNS:";
596  auto altName = ToSBuf(altNamePrefix, *cn);
597  const auto ext = X509V3_EXT_conf_nid(nullptr, nullptr, NID_subject_alt_name, altName.c_str());
598  if (!ext)
599  return false;
600 
601  const bool result = X509_add_ext(cert.get(), ext, -1);
602 
603  X509_EXTENSION_free(ext);
604  return result;
605 }
606 
608 {
609  // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
610  // returns a pointer to the existing subject name. Nothing to clean here.
611  if (properties.mimicCert.get()) {
612  // Leave subject empty if we cannot extract it from true cert.
613  if (X509_NAME *name = X509_get_subject_name(properties.mimicCert.get())) {
614  // X509_set_subject_name will call X509_dup for name
615  X509_set_subject_name(cert.get(), name);
616  }
617  }
618 
619  if (properties.setCommonName || !properties.mimicCert.get()) {
620  // In this case the CN of the certificate given by the user
621  // Ignore errors: it is better to make a certificate with no CN
622  // than to quit ssl-crtd helper because we cannot make a certificate.
623  // Most errors are caused by user input such as huge domain names.
624  (void)replaceCommonName(cert, properties.commonName);
625  }
626 
627  // We should get caCert notBefore and notAfter fields and do not allow
628  // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
629  // fields from caCert.
630  // Currently there is not any way in openssl tollkit to compare two ASN1_TIME
631  // objects.
632  ASN1_TIME *aTime = nullptr;
633  if (!properties.setValidBefore && properties.mimicCert.get())
634  aTime = X509_getm_notBefore(properties.mimicCert.get());
635  if (!aTime && properties.signWithX509.get())
636  aTime = X509_getm_notBefore(properties.signWithX509.get());
637 
638  if (aTime) {
639  if (!X509_set1_notBefore(cert.get(), aTime))
640  return false;
641  } else if (!X509_gmtime_adj(X509_getm_notBefore(cert.get()), (-2)*24*60*60))
642  return false;
643 
644  aTime = nullptr;
645  if (!properties.setValidAfter && properties.mimicCert.get())
646  aTime = X509_getm_notAfter(properties.mimicCert.get());
647  if (!aTime && properties.signWithX509.get())
648  aTime = X509_getm_notAfter(properties.signWithX509.get());
649  if (aTime) {
650  if (!X509_set1_notAfter(cert.get(), aTime))
651  return false;
652  } else if (!X509_gmtime_adj(X509_getm_notAfter(cert.get()), 60*60*24*365*3))
653  return false;
654 
655  int addedExtensions = 0;
656  bool useCommonNameAsAltName = true;
657  // mimic the alias and possibly subjectAltName
658  if (properties.mimicCert.get()) {
659  unsigned char *alStr;
660  int alLen;
661  alStr = X509_alias_get0(properties.mimicCert.get(), &alLen);
662  if (alStr) {
663  X509_alias_set1(cert.get(), alStr, alLen);
664  }
665 
666  // Mimic subjectAltName unless we used a configured CN: browsers reject
667  // certificates with CN unrelated to subjectAltNames.
668  if (!properties.setCommonName) {
669  int pos = X509_get_ext_by_NID(properties.mimicCert.get(), NID_subject_alt_name, -1);
670  X509_EXTENSION *ext=X509_get_ext(properties.mimicCert.get(), pos);
671  if (ext) {
672  if (X509_add_ext(cert.get(), ext, -1))
673  ++addedExtensions;
674  }
675  // We want to mimic the server-sent subjectAltName, not enhance it.
676  useCommonNameAsAltName = false;
677  }
678 
679  addedExtensions += mimicExtensions(cert, properties.mimicCert, properties.signWithX509);
680  }
681 
682  if (useCommonNameAsAltName && addAltNameWithSubjectCn(cert))
683  ++addedExtensions;
684 
685  // According to RFC 5280, using extensions requires v3 certificate.
686  if (addedExtensions)
687  X509_set_version(cert.get(), 2); // value 2 means v3
688 
689  return true;
690 }
691 
692 static bool generateFakeSslCertificate(Security::CertPointer & certToStore, Security::PrivateKeyPointer & pkeyToStore, Ssl::CertificateProperties const &properties, Ssl::BIGNUM_Pointer const &serial)
693 {
694  // Use signing certificates private key as generated certificate private key
695  const auto pkey = properties.signWithPkey ? properties.signWithPkey : CreateRsaPrivateKey();
696  if (!pkey)
697  return false;
698 
699  Security::CertPointer cert(X509_new());
700  if (!cert)
701  return false;
702 
703  // Set pub key and serial given by the caller
704  if (!X509_set_pubkey(cert.get(), pkey.get()))
705  return false;
706  if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial.get()))
707  return false;
708 
709  // Fill the certificate with the required properties
710  if (!buildCertificate(cert, properties))
711  return false;
712 
713  int ret = 0;
714  // Set issuer name, from CA or our subject name for self signed cert
715  if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithX509.get())
716  ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(properties.signWithX509.get()));
717  else // Self signed certificate, set issuer to self
718  ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(cert.get()));
719  if (!ret)
720  return false;
721 
722  const EVP_MD *hash = properties.signHash ? properties.signHash : EVP_get_digestbyname(SQUID_SSL_SIGN_HASH_IF_NONE);
723  assert(hash);
724  /*Now sign the request */
725  if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithPkey.get())
726  ret = Sign(*cert, properties.signWithPkey, *hash);
727  else //else sign with self key (self signed request)
728  ret = Sign(*cert, pkey, *hash);
729 
730  if (!ret)
731  return false;
732 
733  certToStore = std::move(cert);
734  pkeyToStore = std::move(pkey);
735  return true;
736 }
737 
738 static BIGNUM *createCertSerial(unsigned char *md, unsigned int n)
739 {
740 
741  assert(n == 20); //for sha1 n is 20 (for md5 n is 16)
742 
743  BIGNUM *serial = nullptr;
744  serial = BN_bin2bn(md, n, nullptr);
745 
746  // if the serial is "0" set it to '1'
747  if (BN_is_zero(serial) == true)
748  BN_one(serial);
749 
750  // serial size does not exceed 20 bytes
751  assert(BN_num_bits(serial) <= 160);
752 
753  // According the RFC 5280, serial is an 20 bytes ASN.1 INTEGER (a signed big integer)
754  // and the maximum value for X.509 certificate serial number is 2^159-1 and
755  // the minimum 0. If the first bit of the serial is '1' ( eg 2^160-1),
756  // will result to a negative integer.
757  // To handle this, if the produced serial is greater than 2^159-1
758  // truncate the last bit
759  if (BN_is_bit_set(serial, 159))
760  BN_clear_bit(serial, 159);
761 
762  return serial;
763 }
764 
767 static BIGNUM *x509Digest(Security::CertPointer const & cert)
768 {
769  unsigned int n;
770  unsigned char md[EVP_MAX_MD_SIZE];
771 
772  if (!X509_digest(cert.get(),EVP_sha1(),md,&n))
773  return nullptr;
774 
775  return createCertSerial(md, n);
776 }
777 
778 static BIGNUM *x509Pubkeydigest(Security::CertPointer const & cert)
779 {
780  unsigned int n;
781  unsigned char md[EVP_MAX_MD_SIZE];
782 
783  if (!X509_pubkey_digest(cert.get(),EVP_sha1(),md,&n))
784  return nullptr;
785 
786  return createCertSerial(md, n);
787 }
788 
791 static bool createSerial(Ssl::BIGNUM_Pointer &serial, Ssl::CertificateProperties const &properties)
792 {
793  Security::PrivateKeyPointer fakePkey;
794  Security::CertPointer fakeCert;
795 
796  serial.reset(x509Pubkeydigest(properties.signWithX509));
797  if (!serial.get()) {
798  serial.reset(BN_new());
799  BN_zero(serial.get());
800  }
801 
802  if (!generateFakeSslCertificate(fakeCert, fakePkey, properties, serial))
803  return false;
804 
805  // The x509Fingerprint return an SHA1 hash.
806  // both SHA1 hash and maximum serial number size are 20 bytes.
807  BIGNUM *r = x509Digest(fakeCert);
808  if (!r)
809  return false;
810 
811  serial.reset(r);
812  return true;
813 }
814 
815 bool Ssl::generateSslCertificate(Security::CertPointer & certToStore, Security::PrivateKeyPointer & pkeyToStore, Ssl::CertificateProperties const &properties)
816 {
817  Ssl::BIGNUM_Pointer serial;
818 
819  if (!createSerial(serial, properties))
820  return false;
821 
822  return generateFakeSslCertificate(certToStore, pkeyToStore, properties, serial);
823 }
824 
825 bool
827 {
828  bio.reset(BIO_new(BIO_s_file()));
829  if (!bio)
830  return false;
831  if (!BIO_read_filename(bio.get(), filename))
832  return false;
833  return true;
834 }
835 
838 {
839  Assure(bio);
840  ForgetErrors();
841  if (const auto cert = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr))
842  return Security::CertPointer(cert);
843  const auto savedErrno = errno;
844 
845  // PEM_R_NO_START_LINE means OpenSSL could not find a BEGIN CERTIFICATE
846  // marker after successfully reading input. That includes such use cases as
847  // empty input, valid input exhausted by previous extractions, malformed
848  // input, and valid key-only input without the certificate. We cannot
849  // distinguish all these outcomes and treat this error as an EOF condition.
850  if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
851  // consume PEM_R_NO_START_LINE to clean global error queue (if that was
852  // the only error) and/or to let us check for other errors (otherwise)
853  (void)ERR_get_error();
854  if (!ERR_peek_last_error())
855  return nullptr; // EOF without any other errors
856  }
857 
858  ThrowErrors("cannot read a PEM-encoded certificate", savedErrno, Here());
859 }
860 
863 {
864  if (const auto cert = ReadOptionalCertificate(bio))
865  return cert;
866 
867  // PEM_R_NO_START_LINE
868  throw TextException("missing a required PEM-encoded certificate", Here());
869 }
870 
871 bool
872 Ssl::ReadPrivateKey(Ssl::BIO_Pointer &bio, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
873 {
874  assert(bio);
875  if (EVP_PKEY *akey = PEM_read_bio_PrivateKey(bio.get(), nullptr, passwd_callback, nullptr)) {
876  pkey.resetWithoutLocking(akey);
877  return true;
878  }
879  return false;
880 }
881 
882 void
883 Ssl::ReadPrivateKeyFromFile(char const * keyFilename, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
884 {
885  if (!keyFilename)
886  return;
887  Ssl::BIO_Pointer bio;
888  if (!OpenCertsFileForReading(bio, keyFilename))
889  return;
890  ReadPrivateKey(bio, pkey, passwd_callback);
891 }
892 
893 bool
895 {
896  bio.reset(BIO_new(BIO_s_file()));
897  if (!bio)
898  return false;
899  if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
900  return false;
901  return true;
902 }
903 
904 bool
906 {
907  if (!cert || !bio)
908  return false;
909  if (!PEM_write_bio_X509(bio.get(), cert.get()))
910  return false;
911  return true;
912 }
913 
914 bool
915 Ssl::WritePrivateKey(Ssl::BIO_Pointer &bio, const Security::PrivateKeyPointer &pkey)
916 {
917  if (!pkey || !bio)
918  return false;
919  if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), nullptr, nullptr, 0, nullptr, nullptr))
920  return false;
921  return true;
922 }
923 
925 Ssl::OneLineSummary(X509_NAME &name)
926 {
927  return Ssl::UniqueCString(X509_NAME_oneline(&name, nullptr, 0));
928 }
929 
930 bool Ssl::sslDateIsInTheFuture(char const * date)
931 {
932  ASN1_UTCTIME tm;
933  tm.flags = 0;
934  tm.type = 23;
935  tm.data = (unsigned char *)date;
936  tm.length = strlen(date);
937 
938  return (X509_cmp_current_time(&tm) > 0);
939 }
940 
942 static bool asn1timeToGeneralizedTimeStr(ASN1_TIME *aTime, char *buf, int bufLen)
943 {
944  // ASN1_Time holds time to UTCTime or GeneralizedTime form.
945  // UTCTime has the form YYMMDDHHMMSS[Z | [+|-]offset]
946  // GeneralizedTime has the form YYYYMMDDHHMMSS[Z | [+|-] offset]
947 
948  // length should have space for data plus 2 extra bytes for the two extra year fields
949  // plus the '\0' char.
950  if ((aTime->length + 3) > bufLen)
951  return false;
952 
953  char *str;
954  if (aTime->type == V_ASN1_UTCTIME) {
955  if (aTime->data[0] > '5') { // RFC 2459, section 4.1.2.5.1
956  buf[0] = '1';
957  buf[1] = '9';
958  } else {
959  buf[0] = '2';
960  buf[1] = '0';
961  }
962  str = buf +2;
963  } else // if (aTime->type == V_ASN1_GENERALIZEDTIME)
964  str = buf;
965 
966  memcpy(str, aTime->data, aTime->length);
967  str[aTime->length] = '\0';
968  return true;
969 }
970 
971 static int asn1time_cmp(ASN1_TIME *asnTime1, ASN1_TIME *asnTime2)
972 {
973  char strTime1[64], strTime2[64];
974  if (!asn1timeToGeneralizedTimeStr(asnTime1, strTime1, sizeof(strTime1)))
975  return -1;
976  if (!asn1timeToGeneralizedTimeStr(asnTime2, strTime2, sizeof(strTime2)))
977  return -1;
978 
979  return strcmp(strTime1, strTime2);
980 }
981 
982 bool Ssl::certificateMatchesProperties(X509 *cert, CertificateProperties const &properties)
983 {
984  assert(cert);
985 
986  // For non self-signed certificates we have to check if the signing certificate changed
987  if (properties.signAlgorithm != Ssl::algSignSelf) {
988  assert(properties.signWithX509.get());
989  if (X509_check_issued(properties.signWithX509.get(), cert) != X509_V_OK)
990  return false;
991  }
992 
993  X509 *cert2 = properties.mimicCert.get();
994  // If there is not certificate to mimic stop here
995  if (!cert2)
996  return true;
997 
998  if (!properties.setCommonName) {
999  X509_NAME *cert1_name = X509_get_subject_name(cert);
1000  X509_NAME *cert2_name = X509_get_subject_name(cert2);
1001  if (X509_NAME_cmp(cert1_name, cert2_name) != 0)
1002  return false;
1003  } else if (properties.commonName != CommonHostName(cert))
1004  return false;
1005 
1006  if (!properties.setValidBefore) {
1007  const auto aTime = X509_getm_notBefore(cert);
1008  const auto bTime = X509_getm_notBefore(cert2);
1009  if (asn1time_cmp(aTime, bTime) != 0)
1010  return false;
1011  } else if (X509_cmp_current_time(X509_getm_notBefore(cert)) >= 0) {
1012  // notBefore does not exist (=0) or it is in the future (>0)
1013  return false;
1014  }
1015 
1016  if (!properties.setValidAfter) {
1017  const auto aTime = X509_getm_notAfter(cert);
1018  const auto bTime = X509_getm_notAfter(cert2);
1019  if (asn1time_cmp(aTime, bTime) != 0)
1020  return false;
1021  } else if (X509_cmp_current_time(X509_getm_notAfter(cert)) <= 0) {
1022  // notAfter does not exist (0) or it is in the past (<0)
1023  return false;
1024  }
1025 
1026  char *alStr1;
1027  int alLen;
1028  alStr1 = (char *)X509_alias_get0(cert, &alLen);
1029  char *alStr2 = (char *)X509_alias_get0(cert2, &alLen);
1030  if ((!alStr1 && alStr2) || (alStr1 && !alStr2) ||
1031  (alStr1 && alStr2 && strcmp(alStr1, alStr2)) != 0)
1032  return false;
1033 
1034  // Compare subjectAltName extension
1035  STACK_OF(GENERAL_NAME) * cert1_altnames;
1036  cert1_altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr);
1037  STACK_OF(GENERAL_NAME) * cert2_altnames;
1038  cert2_altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert2, NID_subject_alt_name, nullptr, nullptr);
1039  bool match = true;
1040  if (cert1_altnames) {
1041  int numalts = sk_GENERAL_NAME_num(cert1_altnames);
1042  for (int i = 0; match && i < numalts; ++i) {
1043  GENERAL_NAME *aName = sk_GENERAL_NAME_value(cert1_altnames, i);
1044  match = sk_GENERAL_NAME_find(cert2_altnames, aName);
1045  }
1046  } else if (cert2_altnames)
1047  match = false;
1048 
1049  sk_GENERAL_NAME_pop_free(cert1_altnames, GENERAL_NAME_free);
1050  sk_GENERAL_NAME_pop_free(cert2_altnames, GENERAL_NAME_free);
1051 
1052  return match;
1053 }
1054 
1055 static const char *getSubjectEntry(X509 *x509, int nid)
1056 {
1057  static char name[1024] = ""; // stores common name (CN)
1058 
1059  if (!x509)
1060  return nullptr;
1061 
1062  // TODO: What if the entry is a UTF8String? See X509_NAME_get_index_by_NID(3ssl).
1063  const int nameLen = X509_NAME_get_text_by_NID(
1064  X509_get_subject_name(x509),
1065  nid, name, sizeof(name));
1066 
1067  if (nameLen > 0)
1068  return name;
1069 
1070  return nullptr;
1071 }
1072 
1073 const char *Ssl::CommonHostName(X509 *x509)
1074 {
1075  return getSubjectEntry(x509, NID_commonName);
1076 }
1077 
1078 const char *Ssl::getOrganization(X509 *x509)
1079 {
1080  return getSubjectEntry(x509, NID_organizationName);
1081 }
1082 
1083 bool
1085 {
1086  if (!cert1 || ! cert2)
1087  return false;
1088 
1089  int cert1Len;
1090  unsigned char *cert1Asn = nullptr;
1091  cert1Len = ASN1_item_i2d((ASN1_VALUE *)cert1.get(), &cert1Asn, ASN1_ITEM_rptr(X509));
1092 
1093  int cert2Len;
1094  unsigned char *cert2Asn = nullptr;
1095  cert2Len = ASN1_item_i2d((ASN1_VALUE *)cert2.get(), &cert2Asn, ASN1_ITEM_rptr(X509));
1096 
1097  if (cert1Len != cert2Len)
1098  return false;
1099 
1100  bool ret = (memcmp(cert1Asn, cert2Asn, cert1Len) == 0);
1101 
1102  OPENSSL_free(cert1Asn);
1103  OPENSSL_free(cert2Asn);
1104 
1105  return ret;
1106 }
1107 
1108 const ASN1_BIT_STRING *
1110 {
1111  SQUID_CONST_X509_GET0_SIGNATURE_ARGS ASN1_BIT_STRING *sig = nullptr;
1112  SQUID_CONST_X509_GET0_SIGNATURE_ARGS X509_ALGOR *sig_alg = nullptr;
1113 
1114  X509_get0_signature(&sig, &sig_alg, cert.get());
1115  return sig;
1116 }
1117 
static bool generateFakeSslCertificate(Security::CertPointer &certToStore, Security::PrivateKeyPointer &pkeyToStore, Ssl::CertificateProperties const &properties, Ssl::BIGNUM_Pointer const &serial)
Definition: gadgets.cc:692
bool appendCertToMemory(Security::CertPointer const &cert, std::string &bufferToWrite)
Definition: gadgets.cc:169
static bool mimicAuthorityKeyId(Security::CertPointer &cert, Security::CertPointer const &mimicCert, Security::CertPointer const &issuerCert)
Definition: gadgets.cc:359
#define Here()
source code location of the caller
Definition: Here.h:15
std::optional< AnyP::Host > ParseCommonNameAt(X509_NAME &, int)
interprets X.509 Subject or Issuer name entry (at the given position) as CN
Definition: gadgets.cc:550
static bool addAltNameWithSubjectCn(Security::CertPointer &cert)
Definition: gadgets.cc:577
std::unique_ptr< ASN1_INTEGER, HardFun< void, ASN1_INTEGER *, &ASN1_INTEGER_free > > ASN1_INT_Pointer
Definition: gadgets.h:59
Security::CertPointer ReadCertificate(const BIO_Pointer &)
Definition: gadgets.cc:862
static int mimicExtensions(Security::CertPointer &cert, Security::CertPointer const &mimicCert, Security::CertPointer const &issuerCert)
Definition: gadgets.cc:439
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:235
const char * CommonHostName(X509 *x509)
Definition: gadgets.cc:1073
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
std::unique_ptr< AUTHORITY_KEYID, HardFun< void, AUTHORITY_KEYID *, &AUTHORITY_KEYID_free > > AUTHORITY_KEYID_Pointer
Definition: gadgets.h:71
Security::LockingPointer< X509, X509_free_cpp, HardFun< int, X509 *, X509_up_ref > > CertPointer
Definition: forward.h:88
static std::optional< Host > ParseSimpleDomainName(const SBuf &)
Definition: Host.cc:49
SBuf AsnToSBuf(const ASN1_STRING &)
converts ASN1_STRING to SBuf
Definition: gadgets.cc:519
std::unique_ptr< STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_free_wrapper > GENERAL_NAME_STACK_Pointer
Definition: gadgets.h:74
std::unique_ptr< BIO, HardFun< void, BIO *, &BIO_vfree > > BIO_Pointer
Definition: gadgets.h:57
std::unique_ptr< X509_NAME, HardFun< void, X509_NAME *, &X509_NAME_free > > X509_NAME_Pointer
Definition: gadgets.h:65
std::unique_ptr< ASN1_OCTET_STRING, HardFun< void, ASN1_OCTET_STRING *, &ASN1_OCTET_STRING_free > > ASN1_OCTET_STRING_Pointer
Definition: gadgets.h:61
Definition: SBuf.h:93
const char * certSignAlgorithm(int sg)
Definition: gadgets.h:182
static BIGNUM * createCertSerial(unsigned char *md, unsigned int n)
Definition: gadgets.cc:738
a stream manipulator for printing a system call error (if any)
bool ReadPrivateKey(BIO_Pointer &bio, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
Definition: gadgets.cc:872
BIO_Pointer ReadOnlyBioTiedTo(const char *)
Definition: gadgets.cc:218
static const size_t MaxCnLen
Definition: gadgets.cc:232
#define X509_set1_notBefore
Definition: openssl.h:250
bool certificateMatchesProperties(X509 *peer_cert, CertificateProperties const &properties)
Definition: gadgets.cc:982
RSA * EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
Definition: openssl.h:104
void reset()
Forget the raw pointer - unlock if any value was set. Become a nil pointer.
bool CertificatesCmp(const Security::CertPointer &cert1, const Security::CertPointer &cert2)
Definition: gadgets.cc:1084
static const char * getSubjectEntry(X509 *x509, int nid)
Definition: gadgets.cc:1055
bool WriteX509Certificate(BIO_Pointer &bio, const Security::CertPointer &cert)
Definition: gadgets.cc:905
static std::optional< Address > Parse(const char *)
Definition: Address.cc:44
const ASN1_BIT_STRING * X509_get_signature(const Security::CertPointer &)
Definition: gadgets.cc:1109
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:285
static bool buildCertificate(Security::CertPointer &cert, Ssl::CertificateProperties const &properties)
Definition: gadgets.cc:607
std::ostream & ReportAndForgetErrors(std::ostream &)
Definition: gadgets.cc:82
Security::CertPointer ReadOptionalCertificate(const BIO_Pointer &)
Definition: gadgets.cc:837
static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const *serial)
Definition: gadgets.cc:125
static auto Sign(Security::Certificate &cert, const Security::PrivateKeyPointer &key, const EVP_MD &availableDigest)
OpenSSL X509_sign() wrapper.
Definition: gadgets.cc:59
bool OpenCertsFileForReading(BIO_Pointer &bio, const char *filename)
Definition: gadgets.cc:826
void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, const X509 *x)
Definition: openssl.h:219
#define X509_getm_notBefore
Definition: openssl.h:248
std::unique_ptr< X509_EXTENSION, HardFun< void, X509_EXTENSION *, &X509_EXTENSION_free > > X509_EXTENSION_Pointer
Definition: gadgets.h:78
@ algSignEnd
Definition: gadgets.h:169
bool generateSslCertificate(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, CertificateProperties const &properties)
Definition: gadgets.cc:815
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
Definition: Xaction.cc:39
static std::optional< SBuf > ParseAsUtf8(const ASN1_STRING &asnBuffer)
OpenSSL ASN1_STRING_to_UTF8() wrapper.
Definition: gadgets.cc:526
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition: IoManip.h:169
const char * getOrganization(X509 *x509)
Definition: gadgets.cc:1078
const char * CertSignAlgorithmStr[]
Definition: gadgets.cc:278
static std::optional< Host > ParseIp(const Ip::Address &)
converts an already parsed IP address to a Host object
Definition: Host.cc:15
void ForgetErrors()
clear any errors that a TLS library has accumulated in its global storage
Definition: Io.cc:71
#define assert(EX)
Definition: assert.h:17
std::unique_ptr< char, HardFun< void, char *, &OPENSSL_free_for_c_strings > > UniqueCString
Definition: gadgets.h:84
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:239
static bool replaceCommonName(Security::CertPointer &cert, std::string const &rawCn)
Definition: gadgets.cc:235
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
@ algSignSelf
Definition: gadgets.h:169
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition: gadgets.h:237
#define Assure(condition)
Definition: Assure.h:35
static hash_table * hash
Definition: text_backend.cc:41
UniqueCString OneLineSummary(X509_NAME &)
a RAII wrapper for the memory-allocating flavor of X509_NAME_oneline()
Definition: gadgets.cc:925
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
static bool asn1timeToGeneralizedTimeStr(ASN1_TIME *aTime, char *buf, int bufLen)
Print the time represented by a ASN1_TIME struct to a string using GeneralizedTime format.
Definition: gadgets.cc:942
void ReadPrivateKeyFromFile(char const *keyFilename, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
Definition: gadgets.cc:883
#define X509_getm_notAfter
Definition: openssl.h:247
static BIGNUM * x509Digest(Security::CertPointer const &cert)
Definition: gadgets.cc:767
X509 Certificate
Definition: forward.h:79
static bool signWithDigest(const Security::PrivateKeyPointer &key)
whether to supply a digest algorithm name when calling X509_sign() with the given key
Definition: gadgets.cc:20
static bool createSerial(Ssl::BIGNUM_Pointer &serial, Ssl::CertificateProperties const &properties)
Definition: gadgets.cc:791
bool sslDateIsInTheFuture(char const *date)
Definition: gadgets.cc:930
a source code location that is cheap to create, copy, and store
Definition: Here.h:29
std::optional< AnyP::Host > ParseAsSimpleDomainNameOrIp(const SBuf &)
Definition: gadgets.cc:542
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
bool OpenCertsFileForWriting(BIO_Pointer &bio, const char *filename)
Definition: gadgets.cc:894
static BIGNUM * x509Pubkeydigest(Security::CertPointer const &cert)
Definition: gadgets.cc:778
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
void ForgetErrors()
Clear any errors accumulated by OpenSSL in its global storage.
Definition: gadgets.cc:65
bool WritePrivateKey(BIO_Pointer &bio, const Security::PrivateKeyPointer &pkey)
Definition: gadgets.cc:915
#define DBG_IMPORTANT
Definition: Stream.h:38
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: gadgets.h:242
static Security::PrivateKeyPointer CreateRsaPrivateKey()
Definition: gadgets.cc:100
std::unique_ptr< EVP_PKEY_CTX, HardFun< void, EVP_PKEY_CTX *, &EVP_PKEY_CTX_free > > EVP_PKEY_CTX_Pointer
Definition: gadgets.h:67
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition: gadgets.h:238
std::unique_ptr< BIGNUM, HardFun< void, BIGNUM *, &BN_free > > BIGNUM_Pointer
Definition: gadgets.h:55
bool writeCertAndPrivateKeyToMemory(Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey, std::string &bufferToWrite)
Definition: gadgets.cc:145
static void ThrowErrors(const char *const problem, const int savedErrno, const SourceLocation &where)
Definition: gadgets.cc:91
std::string & OnDiskCertificateDbKey(const CertificateProperties &)
Definition: gadgets.cc:315
STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx)
Definition: openssl.h:237
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition: gadgets.h:240
#define X509_set1_notAfter
Definition: openssl.h:249
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
static void printX509Signature(const Security::CertPointer &cert, std::string &out)
Definition: gadgets.cc:301
#define SQUID_SSL_SIGN_HASH_IF_NONE
Definition: gadgets.h:46
T * get() const
Returns raw and possibly nullptr pointer.
static int asn1time_cmp(ASN1_TIME *asnTime1, ASN1_TIME *asnTime2)
Definition: gadgets.cc:971
bool readCertAndPrivateKeyFromMemory(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, char const *bufferToRead)
Definition: gadgets.cc:193

 

Introduction

Documentation

Support

Miscellaneous