title: Google Firebase SSL Certificate - My certificate has a large number of other websites listed
body: <p>Problem: Other domains are listed in my Google Firebase SSL certificate.</p>
  
  <p>I created a firebase project to test firebase authentication emails from Cloud Functions. <a href="https://firebase.jhanley.com" rel="noreferrer">firebase.jhanley.com</a></p>
  
  <p>I have separate code that runs in Cloud Functions that validates SSL certificates for each domain that I own / manage (code below). The primary purpose of this code is to send an email when a domain's SSL certificate is about to expire. Some of our SSL certificates must be renewed manually.</p>
  
  <p>The problem is that my code that checks the SSL certificate is returning a huge number of other domain names for my SSL certificate. When I look at the SSL certificate with Chrome, I also see these other domain names. I do want my site associated with these other sites.</p>
  
  <p>A reduced list of the domains that I see in my SSL certificate for Firebase:</p>
  
  <pre><code>2r5consultoria.com.br
  addlix.com
  admin.migrationcover.ae
  admin.thermoply.com
  akut-med.zeitnachweise.de
  ...
  firebase.jhanley.com
  ...
  </code></pre>
  
  <p><strong>Q) Why is this happening with Firebase SSL and is there a solution?</strong></p>
  
  <p><strong>Q) Does Firebase support installing your own SSL certificate?</strong></p>
  
  <p>Python 3.x code that runs in Cloud Functions that processes SSL certificates by connecting to each domain name from a list.</p>
  
  <p>Note: This code does not have any (known) problems. I am including the source code to create added value for others in the community.</p>
  
  <pre><code>""" Routines to process SSL certificates """
  
  import  sys
  import  datetime
  import  socket
  import  ssl
  import  time
  import  myhtml
  
  g_email_required = False    # This is set during processing if a warning or error was detected
  
  def get_email_requred():
      return g_email_required
  
  def ssl_get_cert(hostname):
      """ This function returns an SSL certificate from a host """
  
      context = ssl.create_default_context()
  
      conn = context.wrap_socket(
          socket.socket(socket.AF_INET),
          server_hostname=hostname)
  
      # 3 second timeout because Google Cloud Functions has runtime limitations
      conn.settimeout(3.0)
  
      try:
          conn.connect((hostname, 443))
      except Exception as ex:
          print("{}: Exception: {}".format(hostname, ex), file=sys.stderr)
          return False, str(ex)
  
      host_ssl_info = conn.getpeercert()
  
      return host_ssl_info, ''
  
  def get_ssl_info(host):
      """ This function retrieves the SSL certificate for host """
      # If we receive an error, retry up to three times waiting 10 seconds each time.
  
      retry = 0
      err = ''
  
      while retry &lt; 3:
          ssl_info, err = ssl_get_cert(host)
  
          if ssl_info is not False:
              return ssl_info, ''
  
          retry += 1
          print('    retrying ...')
          time.sleep(10)
  
      return False, err
  
  def get_ssl_issuer_name(ssl_info):
      """ Return the IssuerName from the SSL certificate """
  
      issuerName = ''
  
      issuer = ssl_info['issuer']
  
      # pylint: disable=line-too-long
      # issuer looks like this:
      # This is a set of a set of a set of key / value pairs.
      # ((('countryName', 'US'),), (('organizationName', "Let's Encrypt"),), (('commonName', "Let's Encrypt Authority X3"),))
  
      for item in issuer:
          # item will look like this as it goes thru the issuer set
          # Note that this is a set of a set
          #
          # (('countryName', 'US'),)
          # (('organizationName', "Let's Encrypt"),)
          # (('commonName', "Let's Encrypt Authority X3"),)
  
          s = item[0]
  
          # s will look like this as it goes thru the isser set
          # Note that this is now a set
          #
          # ('countryName', 'US')
          # ('organizationName', "Let's Encrypt")
          # ('commonName', "Let's Encrypt Authority X3")
  
          # break the set into "key" and "value" pairs
          k = s[0]
          v = s[1]
  
          if k == 'organizationName':
              if v != '':
                  issuerName = v
                  continue
  
          if k == 'commonName':
              if v != '':
                  issuerName = v
  
      return issuerName
  
  def get_ssl_subject_alt_names(ssl_info):
      """ Return the Subject Alt Names """
  
      altNames = ''
  
      subjectAltNames = ssl_info['subjectAltName']
  
      index = 0
      for item in subjectAltNames:
          altNames += item[1]
          index += 1
  
          if index &lt; len(subjectAltNames):
              altNames += ', '
  
      return altNames
  
  def process_hostnames(msg_body, hostnames, days_left):
      """ Process the SSL certificate for each hostname """
  
      # pylint: disable=global-statement
      global g_email_required
  
      ssl_date_fmt = r'%b %d %H:%M:%S %Y %Z'
  
      for host in hostnames:
          f_expired = False
  
          print('Processing host:', host)
  
          ssl_info, err = get_ssl_info(host)
  
          if ssl_info is False:
              msg_body = myhtml.add_row(msg_body, host, err, '', '', '', True)
              g_email_required = True
              continue
  
          #print(ssl_info)
  
          issuerName = get_ssl_issuer_name(ssl_info)
  
          altNames = get_ssl_subject_alt_names(ssl_info)
  
          l_expires = datetime.datetime.strptime(ssl_info['notAfter'], ssl_date_fmt)
  
          remaining = l_expires - datetime.datetime.utcnow()
  
          if remaining &lt; datetime.timedelta(days=0):
              # cert has already expired - uhoh!
              cert_status = "Expired"
              f_expired = True
              g_email_required = True
          elif remaining &lt; datetime.timedelta(days=days_left):
              # expires sooner than the buffer
              cert_status = "Time to Renew"
              f_expired = True
              g_email_required = True
          else:
              # everything is fine
              cert_status = "OK"
              f_expired = False
  
          msg_body = myhtml.add_row(msg_body, host, cert_status, str(l_expires), issuerName, altNames, f_expired)
  
      return msg_body
  </code></pre>