File Source: SSLCertificateDialogModel.java

         /* 
    P/P   *  Method: com.dmdirc.ui.core.dialogs.sslcertificate.SSLCertificateDialogModel__static_init
          */
     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.ui.core.dialogs.sslcertificate;
    24  
    25  import com.dmdirc.CertificateManager;
    26  import com.dmdirc.CertificateManager.CertificateDoesntMatchHostException;
    27  import com.dmdirc.CertificateManager.CertificateNotTrustedException;
    28  
    29  import java.security.cert.CertificateException;
    30  import java.security.cert.CertificateExpiredException;
    31  import java.security.cert.CertificateNotYetValidException;
    32  import java.security.cert.CertificateParsingException;
    33  import java.security.cert.X509Certificate;
    34  import java.util.ArrayList;
    35  import java.util.List;
    36  import java.util.Map;
    37  
    38  /**
    39   * Model for SSL certificate dialogs.
    40   *
    41   * @since 0.6.3m1
    42   * @author chris
    43   */
    44  public class SSLCertificateDialogModel {
    45  
    46      /** The certificate chain that we're displaying information about. */
    47      private final X509Certificate[] chain;
    48  
    49      /** The certificate manager for the connection attempt. */
    50      private final CertificateManager manager;
    51  
    52      /** The list of problems found with the certs, if any. */
    53      private final List<CertificateException> problems;
    54  
    55      /** The text to use if a field isn't present on the certificate. */
    56      private static final String NOTPRESENT = "(not present on certificate)";
    57  
    58      /**
    59       * Creates a new SSLCertificateDialogModel for the specified chain.
    60       *
    61       * @param chain The chain of certificates to display info on
    62       * @param problems A list of problems with the certificates, if any
    63       * @param manager The certificate manager responsible for the certs
    64       */
    65      public SSLCertificateDialogModel(final X509Certificate[] chain,
    66              final List<CertificateException> problems,
                     /* 
    P/P               *  Method: void com.dmdirc.ui.core.dialogs.sslcertificate.SSLCertificateDialogModel(X509Certificate[], List, CertificateManager)
                      * 
                      *  Postconditions:
                      *    this.chain == chain
                      *    init'ed(this.chain)
                      *    this.manager == manager
                      *    init'ed(this.manager)
                      *    this.problems == problems
                      *    init'ed(this.problems)
                      */
    67              final CertificateManager manager) {
    68          this.chain = chain;
    69          this.problems = problems;
    70          this.manager = manager;
    71      }
    72  
    73      /**
    74       * Retrieves the certificate chain that's under question.
    75       *
    76       * @return A list of {@link CertificateChainEntry}s corresponding to the
    77       * certificate chain being questioned.
    78       */
    79      public List<CertificateChainEntry> getCertificateChain() {
                 /* 
    P/P           *  Method: List getCertificateChain()
                  * 
                  *  Preconditions:
                  *    this.chain != null
                  *    this.chain.length <= 232-1
                  *    (soft) this.chain[...] != null
                  *    (soft) this.manager != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.CertificateManager:getDNFieldsFromCert(...)@94 != null
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new ArrayList(getCertificateChain#1)
                  *    new ArrayList(getCertificateChain#1) num objects == 1
                  */
    80          final List<CertificateChainEntry> res = new ArrayList<CertificateChainEntry>();
    81  
    82          boolean first = true;
    83  
    84          for (X509Certificate cert : chain) {
    85              boolean invalid = first && !manager.isValidHost(cert);
    86              first = false;
    87  
    88              try {
    89                  cert.checkValidity();
    90              } catch (CertificateException ex) {
    91                  invalid |= true;
    92              }
    93  
    94              res.add(new CertificateChainEntry(CertificateManager
    95                      .getDNFieldsFromCert(cert).get("CN"),
    96                      manager.isTrusted(cert), invalid));
    97          }
    98  
    99          return res;
   100      }
   101  
   102      /**
   103       * Retrieves displayable information about the certificate with the
   104       * specified index in the chain.
   105       *
   106       * @param index The index of the certificate to request information on
   107       * @return A list of lists of {@link CertificateInformationEntry}s.
   108       */
   109      public List<List<CertificateInformationEntry>> getCertificateInfo(final int index) {
                 /* 
    P/P           *  Method: List getCertificateInfo(int)
                  * 
                  *  Preconditions:
                  *    index >= 0
                  *    this.chain != null
                  *    this.chain.length >= 1
                  *    index < this.chain.length
                  *    (soft) this.chain[...] != null
                  *    (soft) this.manager != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.CertificateManager:getDNFieldsFromCert(...)@134 != null
                  *    java.security.cert.X509Certificate:getNotAfter(...)@128 != null
                  *    java.security.cert.X509Certificate:getNotBefore(...)@126 != null
                  *    java.security.cert.X509Certificate:getSerialNumber(...)@150 != null
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new ArrayList(getCertificateInfo#1)
                  *    new ArrayList(getCertificateInfo#1) num objects == 1
                  */
   110          final List<List<CertificateInformationEntry>> res
   111                  = new ArrayList<List<CertificateInformationEntry>>();
   112          final X509Certificate cert = chain[index];
   113          List<CertificateInformationEntry> group;
   114  
   115          boolean tooOld = false, tooNew = false;
   116  
   117          try {
   118              cert.checkValidity();
   119          } catch (CertificateExpiredException ex) {
   120              tooOld = true;
   121          } catch (CertificateNotYetValidException ex) {
   122              tooNew = true;
   123          }
   124  
   125          group = new ArrayList<CertificateInformationEntry>();
   126          group.add(new CertificateInformationEntry("Valid from",
   127                  cert.getNotBefore().toString(), tooNew, false));
   128          group.add(new CertificateInformationEntry("Valid to",
   129                  cert.getNotAfter().toString(), tooOld, false));
   130          res.add(group);
   131  
   132          final boolean wrongName = index == 0 && !manager.isValidHost(cert);
   133          final String names = getAlternateNames(cert);
   134          final Map<String, String> fields = CertificateManager.getDNFieldsFromCert(cert);
   135  
   136          group = new ArrayList<CertificateInformationEntry>();
   137          addCertField(fields, group, "Common name", "CN", wrongName);
   138  
   139          group.add(new CertificateInformationEntry("Alternate names", 
   140                  names == null ? NOTPRESENT : names, wrongName, names == null));
   141  
   142          addCertField(fields, group, "Organisation", "O", false);
   143          addCertField(fields, group, "Unit", "OU", false);
   144          addCertField(fields, group, "Locality", "L", false);
   145          addCertField(fields, group, "State", "ST", false);
   146          addCertField(fields, group, "Country", "C", false);
   147          res.add(group);
   148  
   149          group = new ArrayList<CertificateInformationEntry>();
   150          group.add(new CertificateInformationEntry("Serial number",
   151                  cert.getSerialNumber().toString(), false, false));
   152          group.add(new CertificateInformationEntry("Algorithm",
   153                  cert.getSigAlgName(), false, false));
   154          group.add(new CertificateInformationEntry("SSL version",
   155                  String.valueOf(cert.getVersion()), false, false));
   156          res.add(group);
   157  
   158          return res;
   159      }
   160  
   161      protected String getAlternateNames(final X509Certificate cert) {
                 /* 
    P/P           *  Method: String getAlternateNames(X509Certificate)
                  * 
                  *  Preconditions:
                  *    (soft) cert != null
                  * 
                  *  Presumptions:
                  *    java.security.cert.X509Certificate:getSubjectAlternativeNames(...)@169 != null
                  *    java.util.Iterator:next(...)@169 != null
                  *    java.util.List:get(...)@170 != null
                  * 
                  *  Postconditions:
                  *    java.lang.StringBuilder:toString(...)._tainted == 0
                  *    return_value in Addr_Set{null,&amp;java.lang.StringBuilder:toString(...)}
                  * 
                  *  Test Vectors:
                  *    java.lang.Integer:intValue(...)@170: {-231..1, 3..6, 8..232-1}, {7}
                  *    java.lang.StringBuilder:length(...)@174: {-231..0}, {1..232-1}
                  *    java.security.cert.X509Certificate:getSubjectAlternativeNames(...)@165: Inverse{null}, Addr_Set{null}
                  */
   162          final StringBuilder res = new StringBuilder();
   163  
   164          try {
   165              if (cert.getSubjectAlternativeNames() == null) {
   166                  return null;
   167              }
   168  
   169              for (List<?> entry : cert.getSubjectAlternativeNames()) {
   170                  final int type = ((Integer) entry.get(0)).intValue();
   171  
   172                  // DNS or IP
   173                  if (type == 2 || type == 7) {
   174                      if (res.length() > 0) {
   175                          res.append(", ");
   176                      }
   177  
   178                      res.append(entry.get(1));
   179                  }
   180              }
   181          } catch (CertificateParsingException ex) {
   182              // Do nothing
   183          }
   184  
   185          return res.toString();
   186      }
   187  
   188      /**
   189       * Adds a field to the specified group.
   190       *
   191       * @param fields The fields extracted from the certiciate
   192       * @param group The group to add an entry to
   193       * @param title The user-friendly title of the field
   194       * @param field The name of the field to look for
   195       * @param invalid Whether or not the field is a cause for concern
   196       */
   197      protected void addCertField(final Map<String, String> fields,
   198              final List<CertificateInformationEntry> group, final String title,
   199              final String field, final boolean invalid) {
                 /* 
    P/P           *  Method: void addCertField(Map, List, String, String, bool)
                  * 
                  *  Preconditions:
                  *    fields != null
                  *    group != null
                  */
   200          group.add(new CertificateInformationEntry(title,
   201                  fields.containsKey(field) ? fields.get(field) : NOTPRESENT, invalid,
   202                  !fields.containsKey(field)));
   203      }
   204  
   205      /**
   206       * Retrieves a list of summary elements to describe the overall status
   207       * of the certificate chain.
   208       *
   209       * @return A list of summary entries
   210       */
   211      public List<CertificateSummaryEntry> getSummary() {
                 /* 
    P/P           *  Method: List getSummary()
                  * 
                  *  Preconditions:
                  *    this.problems != null
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new ArrayList(getSummary#1)
                  *    new ArrayList(getSummary#1) num objects == 1
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@216: {0}, {1}
                  */
   212          final List<CertificateSummaryEntry> res = new ArrayList<CertificateSummaryEntry>();
   213  
   214          boolean outofdate = false, wronghost = false, nottrusted = false;
   215  
   216          for (CertificateException ex : problems) {
   217              if (ex instanceof CertificateExpiredException
   218                      || ex instanceof CertificateNotYetValidException) {
   219                  outofdate = true;
   220              } else if (ex instanceof CertificateDoesntMatchHostException) {
   221                  wronghost = true;
   222              } else if (ex instanceof CertificateNotTrustedException) {
   223                  nottrusted = true;
   224              }
   225          }
   226  
   227          if (outofdate) {
   228              res.add(new CertificateSummaryEntry("One or more certificates are " +
   229                      "not within their validity period", false));
   230          } else {
   231              res.add(new CertificateSummaryEntry("All certificates are " +
   232                      "within their validity period", true));
   233          }
   234  
   235          if (nottrusted) {
   236              res.add(new CertificateSummaryEntry("The certificate is not issued "
   237                      + "by a trusted authority", false));
   238          } else {
   239              res.add(new CertificateSummaryEntry("The certificate chain is "
   240                      + "trusted", true));
   241          }
   242  
   243          if (wronghost) {
   244              res.add(new CertificateSummaryEntry("The certificate is not issued "
   245                      + "to the host you are connecting to", false));
   246          } else {
   247              res.add(new CertificateSummaryEntry("The certificate is issued "
   248                      + "to the host you are connecting to", true));
   249          }
   250  
   251          return res;
   252      }
   253      
   254      /**
   255       * Determines whether or not a response is required from the user about
   256       * this certificate chain.
   257       *
   258       * @return True if a response is required, false otherwise
   259       */
   260      public boolean needsResponse() {
                 /* 
    P/P           *  Method: bool needsResponse()
                  * 
                  *  Preconditions:
                  *    this.problems != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   261          return !problems.isEmpty();
   262      }
   263  
   264      /**
   265       * Retrieves the name of the server to which the user is trying to connect.
   266       *
   267       * @return The name of the server that the user is trying to connect to
   268       */
   269      public String getServerName() {
                 /* 
    P/P           *  Method: String getServerName()
                  * 
                  *  Preconditions:
                  *    this.manager != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   270          return manager.getServerName();
   271      }
   272  
   273      /**
   274       * Performs the specified action on the certificate chain/connection.
   275       * Should only be called once per instance, and only if
   276       * {@link #needsResponse()} returns true.
   277       * 
   278       * @param action The action to be performed
   279       */
   280      public void performAction(final CertificateAction action) {
                 /* 
    P/P           *  Method: void performAction(CertificateAction)
                  * 
                  *  Preconditions:
                  *    this.manager != null
                  *    this.problems != null
                  * 
                  *  Presumptions:
                  *    java.util.List:isEmpty(...)@261 == 0
                  */
   281          if (!needsResponse()) {
   282              throw new IllegalStateException("Can't perform action when "
   283                      + "no action is needed");
   284          }
   285          
   286          manager.setAction(action);
   287      }
   288  
   289  }








SofCheck Inspector Build Version : 2.17854
SSLCertificateDialogModel.java 2009-Jun-25 01:54:24
SSLCertificateDialogModel.class 2009-Sep-02 17:04:12