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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors