/**
   * Retrieves a list of all the alternate names of the specified certificates as a comma-separated
   * string.
   *
   * @param cert The certificate to retrieve alternate names for
   * @return A comma-separated list of alternate names
   */
  protected String getAlternateNames(final X509Certificate cert) {
    final StringBuilder res = new StringBuilder();

    try {
      if (cert.getSubjectAlternativeNames() == null) {
        return null;
      }

      for (List<?> entry : cert.getSubjectAlternativeNames()) {
        final int type = ((Integer) entry.get(0)).intValue();

        // DNS or IP
        if (type == 2 || type == 7) {
          if (res.length() > 0) {
            res.append(", ");
          }

          res.append(entry.get(1));
        }
      }
    } catch (CertificateParsingException ex) {
      // Do nothing
    }

    return res.toString();
  }
  private String hostNameMessage(X509Certificate cert, String hostname) {
    StringBuffer si = new StringBuffer();

    si.append(master.getString(R.string.mtm_hostname_mismatch, hostname));
    si.append("\n\n");
    try {
      Collection<List<?>> sans = cert.getSubjectAlternativeNames();
      if (sans == null) {
        si.append(cert.getSubjectDN());
        si.append("\n");
      } else
        for (List<?> altName : sans) {
          Object name = altName.get(1);
          if (name instanceof String) {
            si.append("[");
            si.append((Integer) altName.get(0));
            si.append("] ");
            si.append(name);
            si.append("\n");
          }
        }
    } catch (CertificateParsingException e) {
      e.printStackTrace();
      si.append("<Parsing error: ");
      si.append(e.getLocalizedMessage());
      si.append(">\n");
    }
    si.append("\n");
    si.append(master.getString(R.string.mtm_connect_anyway));
    si.append("\n\n");
    si.append(master.getString(R.string.mtm_cert_details));
    certDetails(si, cert);
    return si.toString();
  }
  /**
   * Checks the site certificate against the DNS domain name of the site being visited
   *
   * @param certificate The certificate to check
   * @param thisDomain The DNS domain name of the site being visited
   * @return True iff if there is a domain match as specified by RFC2818
   */
  private static boolean matchDns(X509Certificate certificate, String thisDomain) {
    try {
      Collection<?> subjectAltNames = certificate.getSubjectAlternativeNames();
      if (subjectAltNames != null) {
        Iterator<?> i = subjectAltNames.iterator();
        while (i.hasNext()) {
          List<?> altNameEntry = (List<?>) (i.next());
          if ((altNameEntry != null) && (2 <= altNameEntry.size())) {
            Integer altNameType = (Integer) (altNameEntry.get(0));
            if (altNameType != null) {
              if (altNameType.intValue() == ALT_DNS_NAME) {
                String altName = (String) (altNameEntry.get(1));
                if (altName != null) {
                  if (matchDns(thisDomain, altName)) {
                    return true;
                  }
                }
              }
            }
          }
        }
      }
    } catch (CertificateParsingException e) {
      // one way we can get here is if an alternative name starts with
      // '*' character, which is contrary to one interpretation of the
      // spec (a valid DNS name must start with a letter); there is no
      // good way around this

      // NOTE: Mofication of AOSP code: return false on invalid DNS names
      // do not accept certs with invalid DNS names
    }

    return false;
  }
 /**
  * Extracts the array of SubjectAlt DNS names from an X509Certificate. Returns null if there
  * aren't any.
  *
  * <p>Note: Java doesn't appear able to extract international characters from the SubjectAlts. It
  * can only extract international characters from the CN field.
  *
  * <p>(Or maybe the version of OpenSSL I'm using to test isn't storing the international
  * characters correctly in the SubjectAlts?).
  *
  * @param cert X509Certificate
  * @return Array of SubjectALT DNS names stored in the certificate.
  */
 public static String[] getDNSSubjectAlts(X509Certificate cert) {
   LinkedList subjectAltList = new LinkedList();
   Collection c = null;
   try {
     c = cert.getSubjectAlternativeNames();
   } catch (CertificateParsingException cpe) {
     // Should probably log.debug() this?
     cpe.printStackTrace();
   }
   if (c != null) {
     Iterator it = c.iterator();
     while (it.hasNext()) {
       List list = (List) it.next();
       int type = ((Integer) list.get(0)).intValue();
       // If type is 2, then we've got a dNSName
       if (type == 2) {
         String s = (String) list.get(1);
         subjectAltList.add(s);
       }
     }
   }
   if (!subjectAltList.isEmpty()) {
     String[] subjectAlts = new String[subjectAltList.size()];
     subjectAltList.toArray(subjectAlts);
     return subjectAlts;
   } else {
     return null;
   }
 }
  /**
   * Checks the site certificate against the IP domain name of the site being visited
   *
   * @param certificate The certificate to check
   * @param thisDomain The DNS domain name of the site being visited
   * @return True iff if there is a domain match as specified by RFC2818
   */
  private static boolean matchIpAddress(X509Certificate certificate, String thisDomain) {

    try {
      Collection<?> subjectAltNames = certificate.getSubjectAlternativeNames();
      if (subjectAltNames != null) {
        for (Object subjectAltName : subjectAltNames) {
          List<?> altNameEntry = (List<?>) (subjectAltName);
          if ((altNameEntry != null) && (2 <= altNameEntry.size())) {
            Integer altNameType = (Integer) (altNameEntry.get(0));
            if (altNameType != null) {
              if (altNameType == ALT_IPA_NAME) {
                String altName = (String) (altNameEntry.get(1));
                if (altName != null) {
                  if (thisDomain.equalsIgnoreCase(altName)) {
                    return true;
                  }
                }
              }
            }
          }
        }
      }
    } catch (CertificateParsingException e) {
    }

    return false;
  }
 /**
  * Check if the certificate allows use of the given DNS name.
  *
  * <p>From RFC2818: If a subjectAltName extension of type dNSName is present, that MUST be used as
  * the identity. Otherwise, the (most specific) Common Name field in the Subject field of the
  * certificate MUST be used. Although the use of the Common Name is existing practice, it is
  * deprecated and Certification Authorities are encouraged to use the dNSName instead.
  *
  * <p>Matching is performed using the matching rules specified by [RFC2459]. If more than one
  * identity of a given type is present in the certificate (e.g., more than one dNSName name, a
  * match in any one of the set is considered acceptable.)
  */
 private void matchDNS(String expectedName, X509Certificate cert) throws CertificateException {
   Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
   if (subjAltNames != null) {
     boolean foundDNS = false;
     for (List<?> next : subjAltNames) {
       if (((Integer) next.get(0)).intValue() == ALTNAME_DNS) {
         foundDNS = true;
         String dnsName = (String) next.get(1);
         if (isMatched(expectedName, dnsName)) {
           return;
         }
       }
     }
     if (foundDNS) {
       // if certificate contains any subject alt names of type DNS
       // but none match, reject
       throw new CertificateException(
           "No subject alternative DNS " + "name matching " + expectedName + " found.");
     }
   }
   X500Name subjectName = getSubjectX500Name(cert);
   DerValue derValue = subjectName.findMostSpecificAttribute(X500Name.commonName_oid);
   if (derValue != null) {
     try {
       if (isMatched(expectedName, derValue.getAsString())) {
         return;
       }
     } catch (IOException e) {
       // ignore
     }
   }
   String msg = "No name matching " + expectedName + " found";
   throw new CertificateException(msg);
 }
  /**
   * Returns a list of subject alternative names. Any name that is represented as a String by
   * X509Certificate.getSubjectAlternativeNames() is converted to lowercase and returned.
   *
   * @param certificate a certificate
   * @return a list of subject alternative names; list is never null
   * @throws CertificateParsingException if parsing the certificate failed
   */
  public static List<String> getSubjectAlternativeNames(final X509Certificate certificate)
      throws CertificateParsingException {

    final Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
    if (altNames == null) {
      return new ArrayList<>();
    }

    final List<String> result = new ArrayList<>();
    for (final List<?> generalName : altNames) {
      /**
       * generalName has the name type as the first element a String or byte array for the second
       * element. We return any general names that are String types.
       *
       * <p>We don't inspect the numeric name type because some certificates incorrectly put IPs and
       * DNS names under the wrong name types.
       */
      final Object value = generalName.get(1);
      if (value instanceof String) {
        result.add(((String) value).toLowerCase());
      }
    }

    return result;
  }
  public boolean verify(String hostname, SSLSession session) {
    if (trustAllServerCerts) {
      return true;
    }

    boolean approve = true;
    X509Certificate peercert = null;
    String cn = null;

    try {
      X509Certificate[] peercerts = (X509Certificate[]) session.getPeerCertificates();
      peercert = peercerts[0];
      String subjectDN = peercert.getSubjectDN().getName();
      cn = new X500Name(subjectDN).getCommonName();
    } catch (Exception ex) {
      debug.error("AMHostnameVerifier:" + ex.toString());
    }

    if (cn == null) return false;

    if (!sslTrustHosts.isEmpty()) {
      if (sslTrustHosts.contains(cn.toLowerCase())) {
        return true;
      }
    }

    if (resolveIPAddress) {
      try {
        approve =
            InetAddress.getByName(cn)
                .getHostAddress()
                .equals(InetAddress.getByName(hostname).getHostAddress());
      } catch (UnknownHostException ex) {
        if (debug.messageEnabled()) {
          debug.message("AMHostnameVerifier:", ex);
        }
        approve = false;
      }
    } else {
      approve = false;
    }

    if (checkSubjectAltName && !approve) {
      try {
        Iterator i = (Iterator) peercert.getSubjectAlternativeNames().iterator();
        for (; !approve && i.hasNext(); ) {
          approve = compareHosts((GeneralName) i.next(), hostname);
        }
      } catch (Exception ex) {
        return false;
      }
    }

    return approve;
  }
 /**
  * Check if the certificate allows use of the given IP address.
  *
  * <p>From RFC2818: In some cases, the URI is specified as an IP address rather than a hostname.
  * In this case, the iPAddress subjectAltName must be present in the certificate and must exactly
  * match the IP in the URI.
  */
 private static void matchIP(String expectedIP, X509Certificate cert) throws CertificateException {
   Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
   if (subjAltNames == null) {
     throw new CertificateException("No subject alternative names present");
   }
   for (List<?> next : subjAltNames) {
     // For IP address, it needs to be exact match
     if (((Integer) next.get(0)).intValue() == ALTNAME_IP) {
       String ipAddress = (String) next.get(1);
       if (expectedIP.equalsIgnoreCase(ipAddress)) {
         return;
       }
     }
   }
   throw new CertificateException(
       "No subject alternative " + "names matching " + "IP address " + expectedIP + " found");
 }
 private List<String> b(X509Certificate paramX509Certificate) {
   Collection localCollection;
   try {
     localCollection = paramX509Certificate.getSubjectAlternativeNames();
     if (localCollection == null) return Collections.emptyList();
   } catch (CertificateParsingException localCertificateParsingException) {
     c.a("Error parsing certificate", localCertificateParsingException);
     return Collections.emptyList();
   }
   ArrayList localArrayList = new ArrayList();
   Iterator localIterator = localCollection.iterator();
   while (true) {
     if (!localIterator.hasNext()) return localArrayList;
     List localList = (List) localIterator.next();
     if (((Integer) localList.get(0)).intValue() == 2)
       localArrayList.add((String) localList.get(1));
   }
 }
  /**
   * Extract the value of a given SubjectAltName field from a {@link X509Certificate}.
   *
   * @param certificate the certificate.
   * @param field the field number.
   * @return an {@link Optional} containing the value in the field.
   * @see #SUBJECT_ALT_NAME_IP_ADDRESS
   * @see #SUBJECT_ALT_NAME_DNS_NAME
   * @see #SUBJECT_ALT_NAME_URI
   */
  public static Optional<Object> getSubjectAltNameField(X509Certificate certificate, int field) {
    try {
      Collection<List<?>> subjectAltNames = certificate.getSubjectAlternativeNames();
      if (subjectAltNames == null) subjectAltNames = Collections.emptyList();

      for (List<?> idAndValue : subjectAltNames) {
        if (idAndValue != null && idAndValue.size() == 2) {
          if (idAndValue.get(0).equals(field)) {
            return Optional.ofNullable(idAndValue.get(1));
          }
        }
      }

      return Optional.empty();
    } catch (CertificateParsingException e) {
      return Optional.empty();
    }
  }
 public static ArrayList getServername(X509Certificate paramX509Certificate) {
   ArrayList localArrayList = new ArrayList();
   try {
     Collection localCollection = paramX509Certificate.getSubjectAlternativeNames();
     if (localCollection != null) {
       Iterator localIterator = localCollection.iterator();
       while (localIterator.hasNext()) {
         List localList = (List) localIterator.next();
         if (((Integer) localList.get(0)).intValue() == 2) {
           String str2 = (String) localList.get(1);
           localArrayList.add(str2);
         }
       }
       if (localArrayList.size() > 0) return localArrayList;
     }
   } catch (NoSuchMethodError localNoSuchMethodError) {
   } catch (CertificateException localCertificateException) {
   }
   String str1 = extractSubjectAliasName(paramX509Certificate);
   localArrayList.add(str1);
   return localArrayList;
 }
 private static String[] getSubjectAlts(X509Certificate x509certificate, String s) {
   LinkedList linkedlist;
   byte byte0;
   if (isIPAddress(s)) {
     byte0 = 7;
   } else {
     byte0 = 2;
   }
   linkedlist = new LinkedList();
   s = null;
   try {
     x509certificate = x509certificate.getSubjectAlternativeNames();
   }
   // Misplaced declaration of an exception variable
   catch (X509Certificate x509certificate) {
     x509certificate = s;
   }
   if (x509certificate != null) {
     x509certificate = x509certificate.iterator();
     do {
       if (!x509certificate.hasNext()) {
         break;
       }
       s = (List) x509certificate.next();
       if (((Integer) s.get(0)).intValue() == byte0) {
         linkedlist.add((String) s.get(1));
       }
     } while (true);
   }
   if (!linkedlist.isEmpty()) {
     x509certificate = new String[linkedlist.size()];
     linkedlist.toArray(x509certificate);
     return x509certificate;
   } else {
     return null;
   }
 }
 /**
  * Extract identities from certificates exchanged over TLS, based on guidelines from
  * draft-ietf-sip-domain-certs-04.
  *
  * @return list of authenticated identities
  */
 public List<String> extractCertIdentities() throws SSLPeerUnverifiedException {
   if (this.getMessageChannel() instanceof TLSMessageChannel) {
     List<String> certIdentities = new ArrayList<String>();
     Certificate[] certs = getPeerCertificates();
     if (certs == null) {
       if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
         sipStack.getStackLogger().logDebug("No certificates available");
       }
       return certIdentities;
     }
     for (Certificate cert : certs) {
       X509Certificate x509cert = (X509Certificate) cert;
       Collection<List<?>> subjAltNames = null;
       try {
         subjAltNames = x509cert.getSubjectAlternativeNames();
       } catch (CertificateParsingException ex) {
         if (sipStack.isLoggingEnabled()) {
           sipStack.getStackLogger().logError("Error parsing TLS certificate", ex);
         }
       }
       // subjAltName types are defined in rfc2459
       final Integer dnsNameType = 2;
       final Integer uriNameType = 6;
       if (subjAltNames != null) {
         if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
           sipStack.getStackLogger().logDebug("found subjAltNames: " + subjAltNames);
         }
         // First look for a URI in the subjectAltName field
         // as per draft-ietf-sip-domain-certs-04
         for (List<?> altName : subjAltNames) {
           // 0th position is the alt name type
           // 1st position is the alt name data
           if (altName.get(0).equals(uriNameType)) {
             SipURI altNameUri;
             try {
               altNameUri = new AddressFactoryImpl().createSipURI((String) altName.get(1));
               String altHostName = altNameUri.getHost();
               if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
                 sipStack
                     .getStackLogger()
                     .logDebug("found uri " + altName.get(1) + ", hostName " + altHostName);
               }
               certIdentities.add(altHostName);
             } catch (ParseException e) {
               if (sipStack.isLoggingEnabled()) {
                 sipStack
                     .getStackLogger()
                     .logError("certificate contains invalid uri: " + altName.get(1));
               }
             }
           }
         }
         // DNS An implementation MUST accept a domain name system
         // identifier as a SIP domain identity if and only if no other
         // identity is found that matches the "sip" URI type described
         // above.
         if (certIdentities.isEmpty()) {
           for (List<?> altName : subjAltNames) {
             if (altName.get(0).equals(dnsNameType)) {
               if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
                 sipStack.getStackLogger().logDebug("found dns " + altName.get(1));
               }
               certIdentities.add(altName.get(1).toString());
             }
           }
         }
       } else {
         // If and only if the subjectAltName does not appear in the
         // certificate, the implementation MAY examine the CN field of the
         // certificate. If a valid DNS name is found there, the
         // implementation MAY accept this value as a SIP domain identity.
         String dname = x509cert.getSubjectDN().getName();
         String cname = "";
         try {
           Pattern EXTRACT_CN = Pattern.compile(".*CN\\s*=\\s*([\\w*\\.]+).*");
           Matcher matcher = EXTRACT_CN.matcher(dname);
           if (matcher.matches()) {
             cname = matcher.group(1);
             if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
               sipStack.getStackLogger().logDebug("found CN: " + cname + " from DN: " + dname);
             }
             certIdentities.add(cname);
           }
         } catch (Exception ex) {
           if (sipStack.isLoggingEnabled()) {
             sipStack.getStackLogger().logError("exception while extracting CN", ex);
           }
         }
       }
     }
     return certIdentities;
   } else throw new UnsupportedOperationException("Not a TLS channel");
 }