/** * 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"); }