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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors