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

 

Introduction

Documentation

Support

Miscellaneous