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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors