Squid Web Cache master
Loading...
Searching...
No Matches
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"
13#include "ip/Address.h"
14#include "sbuf/Stream.h"
15#include "security/Io.h"
16#include "ssl/gadgets.h"
17
19static bool
20signWithDigest(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
58static auto
59Sign(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
64void
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
81std::ostream &
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
91ThrowErrors(const char * const problem, const int savedErrno, const SourceLocation &where)
92{
93 throw TextException(ToSBuf(problem, ": ",
95 ReportSysError(savedErrno)),
96 where);
97}
98
99static 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
125static 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
145bool 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
169bool 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
193bool 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.
218Ssl::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
232static const size_t MaxCnLen = 64;
233
234// Replace certs common name with the given
235static 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
279 "signTrusted",
280 "signUntrusted",
281 "signSelf",
282 nullptr
283};
284
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
300static void
301printX509Signature(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
314std::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
358static 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
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.
438static 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
518SBuf
519Ssl::AsnToSBuf(const ASN1_STRING &buffer)
520{
521 return SBuf(reinterpret_cast<const char *>(buffer.data), buffer.length);
522}
523
525static std::optional<SBuf>
526ParseAsUtf8(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
541std::optional<AnyP::Host>
543{
544 if (const auto ip = Ip::Address::Parse(SBuf(text).c_str()))
545 return AnyP::Host::ParseIp(*ip);
547}
548
549std::optional<AnyP::Host>
550Ssl::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
576static 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
692static 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
738static 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
767static 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
778static 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
791static 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
815bool 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
825bool
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
871bool
872Ssl::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
882void
883Ssl::ReadPrivateKeyFromFile(char const * keyFilename, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
884{
885 if (!keyFilename)
886 return;
888 if (!OpenCertsFileForReading(bio, keyFilename))
889 return;
890 ReadPrivateKey(bio, pkey, passwd_callback);
891}
892
893bool
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
904bool
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
914bool
915Ssl::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
925Ssl::OneLineSummary(X509_NAME &name)
926{
927 return Ssl::UniqueCString(X509_NAME_oneline(&name, nullptr, 0));
928}
929
930bool 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
942static 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
971static 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
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
1055static 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
1073const char *Ssl::CommonHostName(X509 *x509)
1074{
1075 return getSubjectEntry(x509, NID_commonName);
1076}
1077
1078const char *Ssl::getOrganization(X509 *x509)
1079{
1080 return getSubjectEntry(x509, NID_organizationName);
1081}
1082
1083bool
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
1108const 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
#define Assure(condition)
Definition Assure.h:35
#define Here()
source code location of the caller
Definition Here.h:15
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition IoManip.h:169
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
#define assert(EX)
Definition assert.h:17
#define SQUID_CONST_X509_GET0_SIGNATURE_ARGS
Definition autoconf.h:1433
static std::optional< Host > ParseIp(const Ip::Address &)
converts an already parsed IP address to a Host object
Definition Host.cc:15
static std::optional< Host > ParseSimpleDomainName(const SBuf &)
Definition Host.cc:49
static std::ostream & Extra(std::ostream &)
Definition debug.cc:1316
static std::optional< Address > Parse(const char *)
Definition Address.cc:44
a stream manipulator for printing a system call error (if any)
Definition SBuf.h:94
void reset()
Forget the raw pointer - unlock if any value was set. Become a nil pointer.
T * get() const
Returns raw and possibly nullptr pointer.
a source code location that is cheap to create, copy, and store
Definition Here.h:30
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition gadgets.h:237
Security::CertPointer signWithX509
Certificate to sign the generated request.
Definition gadgets.h:236
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition gadgets.h:240
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition gadgets.h:238
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition gadgets.h:242
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition gadgets.h:239
Security::CertPointer mimicCert
Certificate to mimic.
Definition gadgets.h:235
const EVP_MD * signHash
The signing hash to use.
Definition gadgets.h:243
std::string commonName
A CN to use for the generated certificate.
Definition gadgets.h:241
an std::runtime_error with thrower location info
#define DBG_IMPORTANT
Definition Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
const char * getOrganization(X509 *x509)
Definition gadgets.cc:1078
const char * CommonHostName(X509 *x509)
Definition gadgets.cc:1073
bool CertificatesCmp(const Security::CertPointer &cert1, const Security::CertPointer &cert2)
Definition gadgets.cc:1084
static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const *serial)
Definition gadgets.cc:125
void ReadPrivateKeyFromFile(char const *keyFilename, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
Definition gadgets.cc:883
bool ReadPrivateKey(BIO_Pointer &bio, Security::PrivateKeyPointer &pkey, pem_password_cb *passwd_callback)
Definition gadgets.cc:872
bool OpenCertsFileForWriting(BIO_Pointer &bio, const char *filename)
Definition gadgets.cc:894
bool WritePrivateKey(BIO_Pointer &bio, const Security::PrivateKeyPointer &pkey)
Definition gadgets.cc:915
bool appendCertToMemory(Security::CertPointer const &cert, std::string &bufferToWrite)
Definition gadgets.cc:169
bool sslDateIsInTheFuture(char const *date)
Definition gadgets.cc:930
bool OpenCertsFileForReading(BIO_Pointer &bio, const char *filename)
Definition gadgets.cc:826
std::string & OnDiskCertificateDbKey(const CertificateProperties &)
Definition gadgets.cc:315
bool generateSslCertificate(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, CertificateProperties const &properties)
Definition gadgets.cc:815
bool writeCertAndPrivateKeyToMemory(Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey, std::string &bufferToWrite)
Definition gadgets.cc:145
bool readCertAndPrivateKeyFromMemory(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, char const *bufferToRead)
Definition gadgets.cc:193
bool certificateMatchesProperties(X509 *peer_cert, CertificateProperties const &properties)
Definition gadgets.cc:982
bool WriteX509Certificate(BIO_Pointer &bio, const Security::CertPointer &cert)
Definition gadgets.cc:905
const char * CertAdaptAlgorithmStr[]
Definition gadgets.cc:285
const char * certSignAlgorithm(int sg)
Definition gadgets.h:182
const char * CertSignAlgorithmStr[]
Definition gadgets.cc:278
@ algSignEnd
Definition gadgets.h:169
@ algSignSelf
Definition gadgets.h:169
X509 Certificate
Definition forward.h:79
Security::LockingPointer< X509, X509_free_cpp, HardFun< int, X509 *, X509_up_ref > > CertPointer
Definition forward.h:88
Definition Xaction.cc:40
std::unique_ptr< EVP_PKEY_CTX, HardFun< void, EVP_PKEY_CTX *, &EVP_PKEY_CTX_free > > EVP_PKEY_CTX_Pointer
Definition gadgets.h:67
std::optional< AnyP::Host > ParseAsSimpleDomainNameOrIp(const SBuf &)
Definition gadgets.cc:542
std::unique_ptr< BIO, HardFun< void, BIO *, &BIO_vfree > > BIO_Pointer
Definition gadgets.h:57
std::unique_ptr< BIGNUM, HardFun< void, BIGNUM *, &BN_free > > BIGNUM_Pointer
Definition gadgets.h:55
std::unique_ptr< ASN1_OCTET_STRING, HardFun< void, ASN1_OCTET_STRING *, &ASN1_OCTET_STRING_free > > ASN1_OCTET_STRING_Pointer
Definition gadgets.h:61
std::ostream & ReportAndForgetErrors(std::ostream &)
Definition gadgets.cc:82
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
Security::CertPointer ReadOptionalCertificate(const BIO_Pointer &)
Definition gadgets.cc:837
const ASN1_BIT_STRING * X509_get_signature(const Security::CertPointer &)
Definition gadgets.cc:1109
UniqueCString OneLineSummary(X509_NAME &)
a RAII wrapper for the memory-allocating flavor of X509_NAME_oneline()
Definition gadgets.cc:925
Security::CertPointer ReadCertificate(const BIO_Pointer &)
Definition gadgets.cc:862
std::unique_ptr< STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_free_wrapper > GENERAL_NAME_STACK_Pointer
Definition gadgets.h:74
BIO_Pointer ReadOnlyBioTiedTo(const char *)
Definition gadgets.cc:218
SBuf AsnToSBuf(const ASN1_STRING &)
converts ASN1_STRING to SBuf
Definition gadgets.cc:519
std::unique_ptr< X509_NAME, HardFun< void, X509_NAME *, &X509_NAME_free > > X509_NAME_Pointer
Definition gadgets.h:65
std::unique_ptr< ASN1_INTEGER, HardFun< void, ASN1_INTEGER *, &ASN1_INTEGER_free > > ASN1_INT_Pointer
Definition gadgets.h:59
std::unique_ptr< X509_EXTENSION, HardFun< void, X509_EXTENSION *, &X509_EXTENSION_free > > X509_EXTENSION_Pointer
Definition gadgets.h:78
std::unique_ptr< char, HardFun< void, char *, &OPENSSL_free_for_c_strings > > UniqueCString
Definition gadgets.h:84
void ForgetErrors()
Clear any errors accumulated by OpenSSL in its global storage.
Definition gadgets.cc:65
std::unique_ptr< AUTHORITY_KEYID, HardFun< void, AUTHORITY_KEYID *, &AUTHORITY_KEYID_free > > AUTHORITY_KEYID_Pointer
Definition gadgets.h:71
#define X509_getm_notAfter
Definition openssl.h:247
#define X509_getm_notBefore
Definition openssl.h:248
#define X509_set1_notBefore
Definition openssl.h:250
void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, const X509 *x)
Definition openssl.h:219
STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx)
Definition openssl.h:237
RSA * EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
Definition openssl.h:104
#define X509_set1_notAfter
Definition openssl.h:249
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition Stream.h:63
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 replaceCommonName(Security::CertPointer &cert, std::string const &rawCn)
Definition gadgets.cc:235
static std::optional< SBuf > ParseAsUtf8(const ASN1_STRING &asnBuffer)
OpenSSL ASN1_STRING_to_UTF8() wrapper.
Definition gadgets.cc:526
static auto Sign(Security::Certificate &cert, const Security::PrivateKeyPointer &key, const EVP_MD &availableDigest)
OpenSSL X509_sign() wrapper.
Definition gadgets.cc:59
static bool buildCertificate(Security::CertPointer &cert, Ssl::CertificateProperties const &properties)
Definition gadgets.cc:607
static void printX509Signature(const Security::CertPointer &cert, std::string &out)
Definition gadgets.cc:301
static BIGNUM * x509Digest(Security::CertPointer const &cert)
Definition gadgets.cc:767
static BIGNUM * createCertSerial(unsigned char *md, unsigned int n)
Definition gadgets.cc:738
static Security::PrivateKeyPointer CreateRsaPrivateKey()
Definition gadgets.cc:100
static BIGNUM * x509Pubkeydigest(Security::CertPointer const &cert)
Definition gadgets.cc:778
static int mimicExtensions(Security::CertPointer &cert, Security::CertPointer const &mimicCert, Security::CertPointer const &issuerCert)
Definition gadgets.cc:439
static const size_t MaxCnLen
Definition gadgets.cc:232
static bool createSerial(Ssl::BIGNUM_Pointer &serial, Ssl::CertificateProperties const &properties)
Definition gadgets.cc:791
static bool mimicAuthorityKeyId(Security::CertPointer &cert, Security::CertPointer const &mimicCert, Security::CertPointer const &issuerCert)
Definition gadgets.cc:359
static const char * getSubjectEntry(X509 *x509, int nid)
Definition gadgets.cc:1055
static bool generateFakeSslCertificate(Security::CertPointer &certToStore, Security::PrivateKeyPointer &pkeyToStore, Ssl::CertificateProperties const &properties, Ssl::BIGNUM_Pointer const &serial)
Definition gadgets.cc:692
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
static bool addAltNameWithSubjectCn(Security::CertPointer &cert)
Definition gadgets.cc:577
static int asn1time_cmp(ASN1_TIME *asnTime1, ASN1_TIME *asnTime2)
Definition gadgets.cc:971
static void ThrowErrors(const char *const problem, const int savedErrno, const SourceLocation &where)
Definition gadgets.cc:91
#define SQUID_SSL_SIGN_HASH_IF_NONE
Definition gadgets.h:46
SBuf text("GET http://resource.com/path HTTP/1.1\r\n" "Host: resource.com\r\n" "Cookie: laijkpk3422r j1noin \r\n" "\r\n")
static hash_table * hash