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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors