public boolean verify()

in src/main/java/com/amazon/redshift/ssl/RedshiftjdbcHostnameVerifier.java [79:229]


  public boolean verify(String hostname, SSLSession session) {
    X509Certificate[] peerCerts;
    try {
      peerCerts = (X509Certificate[]) session.getPeerCertificates();
    } catch (SSLPeerUnverifiedException e) {
    	if (RedshiftLogger.isEnable() && logger != null)
	      logger.log(LogLevel.ERROR,
	          GT.tr("Unable to parse X509Certificate for hostname {0}", hostname), e);
      return false;
    }
    if (peerCerts == null || peerCerts.length == 0) {
    	if (RedshiftLogger.isEnable() && logger != null)
    		logger.log(LogLevel.ERROR,
          GT.tr("No certificates found for hostname {0}", hostname));
      return false;
    }

    String canonicalHostname;
    if (hostname.startsWith("[") && hostname.endsWith("]")) {
      // IPv6 address like [2001:db8:0:1:1:1:1:1]
      canonicalHostname = hostname.substring(1, hostname.length() - 1);
    } else {
      // This converts unicode domain name to ASCII
      try {
        canonicalHostname = IDN.toASCII(hostname);
      	if (RedshiftLogger.isEnable() && logger != null) {
          logger.log(LogLevel.DEBUG, "Canonical host name for {0} is {1}",
              new Object[]{hostname, canonicalHostname});
        }
      } catch (IllegalArgumentException e) {
        // e.g. hostname is invalid
      	if (RedshiftLogger.isEnable() && logger != null)      	
      		logger.log(LogLevel.ERROR,
            GT.tr("Hostname {0} is invalid", hostname), e);
        return false;
      }
    }

    X509Certificate serverCert = peerCerts[0];

    // Check for Subject Alternative Names (see RFC 6125)

    Collection<List<?>> subjectAltNames;
    try {
      subjectAltNames = serverCert.getSubjectAlternativeNames();
      if (subjectAltNames == null) {
        subjectAltNames = Collections.emptyList();
      }
    } catch (CertificateParsingException e) {
    	if (RedshiftLogger.isEnable() && logger != null)
    		logger.log(LogLevel.ERROR, 
          GT.tr("Unable to parse certificates for hostname {0}", hostname), e);
      return false;
    }

    boolean anyDnsSan = false;
    /*
     * Each item in the SAN collection is a 2-element list.
     * See {@link X509Certificate#getSubjectAlternativeNames}
     * The first element in each list is a number indicating the type of entry.
     */
    for (List<?> sanItem : subjectAltNames) {
      if (sanItem.size() != 2) {
        continue;
      }
      Integer sanType = (Integer) sanItem.get(0);
      if (sanType == null) {
        // just in case
        continue;
      }
      if (sanType != TYPE_IP_ADDRESS && sanType != TYPE_DNS_NAME) {
        continue;
      }
      String san = (String) sanItem.get(1);
      if (sanType == TYPE_IP_ADDRESS && san.startsWith("*")) {
        // Wildcards should not be present in the IP Address field
        continue;
      }
      anyDnsSan |= sanType == TYPE_DNS_NAME;
      if (verifyHostName(canonicalHostname, san)) {
      	if (RedshiftLogger.isEnable() && logger != null) {
          logger.log(LogLevel.DEBUG,
              GT.tr("Server name validation pass for {0}, subjectAltName {1}", hostname, san));
        }
        return true;
      }
    }

    if (anyDnsSan) {
      /*
       * RFC2818, section 3.1 (I bet you won't recheck :)
       * 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.
       */
    	if (RedshiftLogger.isEnable() && logger != null)
    		logger.log(LogLevel.ERROR,
          GT.tr("Server name validation failed: certificate for host {0} dNSName entries subjectAltName,"
              + " but none of them match. Assuming server name validation failed", hostname));
      return false;
    }

    // Last attempt: no DNS Subject Alternative Name entries detected, try common name
    LdapName dn;
    try {
      dn = new LdapName(serverCert.getSubjectX500Principal().getName(X500Principal.RFC2253));
    } catch (InvalidNameException e) {
    	if (RedshiftLogger.isEnable() && logger != null)
	      logger.log(LogLevel.ERROR,
          GT.tr("Server name validation failed: unable to extract common name"
              + " from X509Certificate for hostname {0}", hostname), e);
      return false;
    }

    List<String> commonNames = new ArrayList<String>(1);
    for (Rdn rdn : dn.getRdns()) {
      if ("CN".equals(rdn.getType())) {
        commonNames.add((String) rdn.getValue());
      }
    }
    if (commonNames.isEmpty()) {
    	if (RedshiftLogger.isEnable() && logger != null)
    		logger.log(LogLevel.ERROR,
          GT.tr("Server name validation failed: certificate for hostname {0} has no DNS subjectAltNames,"
                  + " and it CommonName is missing as well",
              hostname));
      return false;
    }
    if (commonNames.size() > 1) {
      /*
       * RFC2818, section 3.1
       * 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
       *
       * The sort is from less specific to most specific.
       */
      Collections.sort(commonNames, HOSTNAME_PATTERN_COMPARATOR);
    }
    String commonName = commonNames.get(commonNames.size() - 1);
    boolean result = verifyHostName(canonicalHostname, commonName);
    if (!result) {
    	if (RedshiftLogger.isEnable() && logger != null)
    		logger.log(LogLevel.ERROR,
          GT.tr("Server name validation failed: hostname {0} does not match common name {1}",
              hostname, commonName));
    }
    return result;
  }