Save This Page
Home » Open-JDK-6.b17-src » sun.security » validator » [javadoc | source]
    1   /*
    2    * Copyright 2002-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package sun.security.validator;
   27   
   28   import java.util;
   29   
   30   import java.security.cert;
   31   
   32   import sun.security.x509.NetscapeCertTypeExtension;
   33   
   34   /**
   35    * Class to check if an end entity cert is suitable for use in some
   36    * context.<p>
   37    *
   38    * This class is used internally by the validator. Currently, seven variants
   39    * are supported defined as VAR_XXX constants in the Validator class:
   40    * <ul>
   41    * <li>Generic. No additional requirements, all certificates are ok.
   42    *
   43    * <li>TLS server. Requires that a String parameter is passed to
   44    * validate that specifies the name of the TLS key exchange algorithm
   45    * in use. See the JSSE X509TrustManager spec for details.
   46    *
   47    * <li>TLS client.
   48    *
   49    * <li>Code signing.
   50    *
   51    * <li>JCE code signing. Some early JCE code signing certs issued to
   52    * providers had incorrect extensions. In this mode the checks
   53    * are relaxed compared to standard code signing checks in order to
   54    * allow these certificates to pass.
   55    *
   56    * <li>Plugin code signing. WebStart and Plugin require their own variant
   57    * which is equivalent to VAR_CODE_SIGNING with additional checks for
   58    * compatibility/special cases. See also PKIXValidator.
   59    *
   60    * <li>TSA Server (see RFC 3161, section 2.3).
   61    *
   62    * </ul>
   63    *
   64    * @author Andreas Sterbenz
   65    */
   66   class EndEntityChecker {
   67   
   68       // extended key usage OIDs for TLS server, TLS client, code signing
   69       // and any usage
   70   
   71       private final static String OID_EXTENDED_KEY_USAGE =
   72                                   SimpleValidator.OID_EXTENDED_KEY_USAGE;
   73   
   74       private final static String OID_EKU_TLS_SERVER = "1.3.6.1.5.5.7.3.1";
   75   
   76       private final static String OID_EKU_TLS_CLIENT = "1.3.6.1.5.5.7.3.2";
   77   
   78       private final static String OID_EKU_CODE_SIGNING = "1.3.6.1.5.5.7.3.3";
   79   
   80       private final static String OID_EKU_TIME_STAMPING = "1.3.6.1.5.5.7.3.8";
   81   
   82       private final static String OID_EKU_ANY_USAGE = "2.5.29.37.0";
   83   
   84       // the Netscape Server-Gated-Cryptography EKU extension OID
   85       private final static String OID_EKU_NS_SGC = "2.16.840.1.113730.4.1";
   86   
   87       // the Microsoft Server-Gated-Cryptography EKU extension OID
   88       private final static String OID_EKU_MS_SGC = "1.3.6.1.4.1.311.10.3.3";
   89   
   90       private final static String NSCT_SSL_CLIENT =
   91                                   NetscapeCertTypeExtension.SSL_CLIENT;
   92   
   93       private final static String NSCT_SSL_SERVER =
   94                                   NetscapeCertTypeExtension.SSL_SERVER;
   95   
   96       private final static String NSCT_CODE_SIGNING =
   97                                   NetscapeCertTypeExtension.OBJECT_SIGNING;
   98   
   99       // bit numbers in the key usage extension
  100       private final static int KU_SIGNATURE = 0;
  101       private final static int KU_KEY_ENCIPHERMENT = 2;
  102       private final static int KU_KEY_AGREEMENT = 4;
  103   
  104       // TLS key exchange algorithms requiring digitalSignature key usage
  105       private final static Collection<String> KU_SERVER_SIGNATURE =
  106           Arrays.asList("DHE_DSS", "DHE_RSA", "ECDHE_ECDSA", "ECDHE_RSA",
  107               "RSA_EXPORT", "UNKNOWN");
  108   
  109       // TLS key exchange algorithms requiring keyEncipherment key usage
  110       private final static Collection<String> KU_SERVER_ENCRYPTION =
  111           Arrays.asList("RSA");
  112   
  113       // TLS key exchange algorithms requiring keyAgreement key usage
  114       private final static Collection<String> KU_SERVER_KEY_AGREEMENT =
  115           Arrays.asList("DH_DSS", "DH_RSA", "ECDH_ECDSA", "ECDH_RSA");
  116   
  117       // variant of this end entity cert checker
  118       private final String variant;
  119   
  120       // type of the validator this checker belongs to
  121       private final String type;
  122   
  123       private EndEntityChecker(String type, String variant) {
  124           this.type = type;
  125           this.variant = variant;
  126       }
  127   
  128       static EndEntityChecker getInstance(String type, String variant) {
  129           return new EndEntityChecker(type, variant);
  130       }
  131   
  132       void check(X509Certificate cert, Object parameter)
  133               throws CertificateException {
  134           if (variant.equals(Validator.VAR_GENERIC)) {
  135               // no checks
  136               return;
  137           } else if (variant.equals(Validator.VAR_TLS_SERVER)) {
  138               checkTLSServer(cert, (String)parameter);
  139           } else if (variant.equals(Validator.VAR_TLS_CLIENT)) {
  140               checkTLSClient(cert);
  141           } else if (variant.equals(Validator.VAR_CODE_SIGNING)) {
  142               checkCodeSigning(cert);
  143           } else if (variant.equals(Validator.VAR_JCE_SIGNING)) {
  144               checkCodeSigning(cert);
  145           } else if (variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING)) {
  146               checkCodeSigning(cert);
  147           } else if (variant.equals(Validator.VAR_TSA_SERVER)) {
  148               checkTSAServer(cert);
  149           } else {
  150               throw new CertificateException("Unknown variant: " + variant);
  151           }
  152       }
  153   
  154       /**
  155        * Utility method returning the Set of critical extensions for
  156        * certificate cert (never null).
  157        */
  158       private Set<String> getCriticalExtensions(X509Certificate cert) {
  159           Set<String> exts = cert.getCriticalExtensionOIDs();
  160           if (exts == null) {
  161               exts = Collections.emptySet();
  162           }
  163           return exts;
  164       }
  165   
  166       /**
  167        * Utility method checking if there are any unresolved critical extensions.
  168        * @throws CertificateException if so.
  169        */
  170       private void checkRemainingExtensions(Set<String> exts)
  171               throws CertificateException {
  172           // basic constraints irrelevant in EE certs
  173           exts.remove(SimpleValidator.OID_BASIC_CONSTRAINTS);
  174           if (!exts.isEmpty()) {
  175               throw new CertificateException("Certificate contains unsupported "
  176                   + "critical extensions: " + exts);
  177           }
  178       }
  179   
  180       /**
  181        * Utility method checking if the extended key usage extension in
  182        * certificate cert allows use for expectedEKU.
  183        */
  184       private boolean checkEKU(X509Certificate cert, Set<String> exts,
  185               String expectedEKU) throws CertificateException {
  186           List<String> eku = cert.getExtendedKeyUsage();
  187           if (eku == null) {
  188               return true;
  189           }
  190           return eku.contains(expectedEKU) || eku.contains(OID_EKU_ANY_USAGE);
  191       }
  192   
  193       /**
  194        * Utility method checking if bit 'bit' is set in this certificates
  195        * key usage extension.
  196        * @throws CertificateException if not
  197        */
  198       private boolean checkKeyUsage(X509Certificate cert, int bit)
  199               throws CertificateException {
  200           boolean[] keyUsage = cert.getKeyUsage();
  201           if (keyUsage == null) {
  202               return true;
  203           }
  204           return (keyUsage.length > bit) && keyUsage[bit];
  205       }
  206   
  207       /**
  208        * Check whether this certificate can be used for TLS client
  209        * authentication.
  210        * @throws CertificateException if not.
  211        */
  212       private void checkTLSClient(X509Certificate cert)
  213               throws CertificateException {
  214           Set<String> exts = getCriticalExtensions(cert);
  215   
  216           if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
  217               throw new ValidatorException
  218                   ("KeyUsage does not allow digital signatures",
  219                   ValidatorException.T_EE_EXTENSIONS, cert);
  220           }
  221   
  222           if (checkEKU(cert, exts, OID_EKU_TLS_CLIENT) == false) {
  223               throw new ValidatorException("Extended key usage does not "
  224                   + "permit use for TLS client authentication",
  225                   ValidatorException.T_EE_EXTENSIONS, cert);
  226           }
  227   
  228           if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_CLIENT)) {
  229               throw new ValidatorException
  230                   ("Netscape cert type does not permit use for SSL client",
  231                   ValidatorException.T_EE_EXTENSIONS, cert);
  232           }
  233   
  234           // remove extensions we checked
  235           exts.remove(SimpleValidator.OID_KEY_USAGE);
  236           exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);
  237           exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);
  238   
  239           checkRemainingExtensions(exts);
  240       }
  241   
  242       /**
  243        * Check whether this certificate can be used for TLS server authentication
  244        * using the specified authentication type parameter. See X509TrustManager
  245        * specification for details.
  246        * @throws CertificateException if not.
  247        */
  248       private void checkTLSServer(X509Certificate cert, String parameter)
  249               throws CertificateException {
  250           Set<String> exts = getCriticalExtensions(cert);
  251   
  252           if (KU_SERVER_ENCRYPTION.contains(parameter)) {
  253               if (checkKeyUsage(cert, KU_KEY_ENCIPHERMENT) == false) {
  254                   throw new ValidatorException
  255                           ("KeyUsage does not allow key encipherment",
  256                           ValidatorException.T_EE_EXTENSIONS, cert);
  257               }
  258           } else if (KU_SERVER_SIGNATURE.contains(parameter)) {
  259               if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
  260                   throw new ValidatorException
  261                           ("KeyUsage does not allow digital signatures",
  262                           ValidatorException.T_EE_EXTENSIONS, cert);
  263               }
  264           } else if (KU_SERVER_KEY_AGREEMENT.contains(parameter)) {
  265               if (checkKeyUsage(cert, KU_KEY_AGREEMENT) == false) {
  266                   throw new ValidatorException
  267                           ("KeyUsage does not allow key agreement",
  268                           ValidatorException.T_EE_EXTENSIONS, cert);
  269               }
  270           } else {
  271               throw new CertificateException("Unknown authType: " + parameter);
  272           }
  273   
  274           if (checkEKU(cert, exts, OID_EKU_TLS_SERVER) == false) {
  275               // check for equivalent but now obsolete Server-Gated-Cryptography
  276               // (aka Step-Up, 128 bit) EKU OIDs
  277               if ((checkEKU(cert, exts, OID_EKU_MS_SGC) == false) &&
  278                   (checkEKU(cert, exts, OID_EKU_NS_SGC) == false)) {
  279                   throw new ValidatorException
  280                       ("Extended key usage does not permit use for TLS "
  281                       + "server authentication",
  282                       ValidatorException.T_EE_EXTENSIONS, cert);
  283               }
  284           }
  285   
  286           if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_SSL_SERVER)) {
  287               throw new ValidatorException
  288                   ("Netscape cert type does not permit use for SSL server",
  289                   ValidatorException.T_EE_EXTENSIONS, cert);
  290           }
  291   
  292           // remove extensions we checked
  293           exts.remove(SimpleValidator.OID_KEY_USAGE);
  294           exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);
  295           exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);
  296   
  297           checkRemainingExtensions(exts);
  298       }
  299   
  300       /**
  301        * Check whether this certificate can be used for code signing.
  302        * @throws CertificateException if not.
  303        */
  304       private void checkCodeSigning(X509Certificate cert)
  305               throws CertificateException {
  306           Set<String> exts = getCriticalExtensions(cert);
  307   
  308           if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
  309               throw new ValidatorException
  310                   ("KeyUsage does not allow digital signatures",
  311                   ValidatorException.T_EE_EXTENSIONS, cert);
  312           }
  313   
  314           if (checkEKU(cert, exts, OID_EKU_CODE_SIGNING) == false) {
  315               throw new ValidatorException
  316                   ("Extended key usage does not permit use for code signing",
  317                   ValidatorException.T_EE_EXTENSIONS, cert);
  318           }
  319   
  320           // do not check Netscape cert type for JCE code signing checks
  321           // (some certs were issued with incorrect extensions)
  322           if (variant.equals(Validator.VAR_JCE_SIGNING) == false) {
  323               if (!SimpleValidator.getNetscapeCertTypeBit(cert, NSCT_CODE_SIGNING)) {
  324                   throw new ValidatorException
  325                       ("Netscape cert type does not permit use for code signing",
  326                       ValidatorException.T_EE_EXTENSIONS, cert);
  327               }
  328               exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE);
  329           }
  330   
  331           // remove extensions we checked
  332           exts.remove(SimpleValidator.OID_KEY_USAGE);
  333           exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);
  334   
  335           checkRemainingExtensions(exts);
  336       }
  337   
  338       /**
  339        * Check whether this certificate can be used by a time stamping authority
  340        * server (see RFC 3161, section 2.3).
  341        * @throws CertificateException if not.
  342        */
  343       private void checkTSAServer(X509Certificate cert)
  344               throws CertificateException {
  345           Set<String> exts = getCriticalExtensions(cert);
  346   
  347           if (checkKeyUsage(cert, KU_SIGNATURE) == false) {
  348               throw new ValidatorException
  349                   ("KeyUsage does not allow digital signatures",
  350                   ValidatorException.T_EE_EXTENSIONS, cert);
  351           }
  352   
  353           if (cert.getExtendedKeyUsage() == null) {
  354               throw new ValidatorException
  355                   ("Certificate does not contain an extended key usage " +
  356                   "extension required for a TSA server",
  357                   ValidatorException.T_EE_EXTENSIONS, cert);
  358           }
  359   
  360           if (checkEKU(cert, exts, OID_EKU_TIME_STAMPING) == false) {
  361               throw new ValidatorException
  362                   ("Extended key usage does not permit use for TSA server",
  363                   ValidatorException.T_EE_EXTENSIONS, cert);
  364           }
  365   
  366           // remove extensions we checked
  367           exts.remove(SimpleValidator.OID_KEY_USAGE);
  368           exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE);
  369   
  370           checkRemainingExtensions(exts);
  371       }
  372   }

Save This Page
Home » Open-JDK-6.b17-src » sun.security » validator » [javadoc | source]