RFR 8140422: Add mechanism to allow non default root CAs to be not subject to algorithm restrictions

Sean Mullan sean.mullan at oracle.com
Tue Mar 8 21:55:27 UTC 2016


You should also copy build-dev on the next iteration since there are a
few Makefile changes.

On 02/29/2016 11:55 AM, Anthony Scarpino wrote:
> I need a code review of this change:
>
> http://cr.openjdk.java.net/~ascarpino/8140422/webrev/
>
> Currently CertPath algorithm restrictions allow or deny all
> certificates.  This change adds the ability to reject certificate chains
> that contain a restricted algorithm and the chain terminates at a root
> CA; therefore, allowing a self-signed or chain that does not terminate
> at a root CA.
>
> https://bugs.openjdk.java.net/browse/JDK-8140422

Looks good, but had a few comments as I went through ...

java.security
-------------

  551 #   "cacerts" prohibits the algorithm only if it is used in a
  552 #     certificate chain that terminates at a distribution provided
  553 #     trust anchor in the lib/security/cacerts keystore. All other
  554 #     chains are not affected. Example: to apply this constraint
  555 #     to SHA-1 certificates, include the following:  "SHA1 cacerts"

Suggest rewording in middle part: "... at a trust anchor in the
lib/security/cacerts.fingerprints file which is initially seeded with 
the fingerprints of the certificates in the lib/security/cacerts keystore."

Also, add the following sentence: "If the cacerts constraint is not set,
then all chains using the specified algorithm are restricted."

  563 # All DisabledAlgorithms are processed in the order defined in the
  564 # property.  This requires lower keysize constraints to be specified
  565 # before larger keysize constraints of the same algorithm.

Is this still an issue? Constraints of the same algorithm are evaluated
as an AND, so the order should not matter (I think).

CACertsHasher
-------------

I think it would be useful to emit the subject DN of the certificate as 
a comment (ex: "# CN=RootsRUs, ...") above each fingerprint, as it would 
help associate the fingerprint with the root. Then, you can ignore 
comments when you parse the file in AnchorCertificates.

AnchorCertificates
------------------

   38 /**
   39  * The purpose of this class is to determine if a trust anchor 
certificate
   40  * is one of the default trust anchors that comes pre-installed 
with the JRE
   41  * in the cacerts file. A locally installed trust anchor would not 
be a default
   42  * trust anchor
   43  */

The determination is based off the cacerts.fingerprints file, so maybe a 
better wording is: "The purpose of this class is to determine if a trust 
anchor certificate is in the cacerts.fingerprints file which is 
initially seeded with the fingerprints of the certificates in the 
cacerts file. A trust anchor that is subsequently added to the cacerts 
file but not the cacerts.fingerprints file would not be a match."

   74                         debug.println("Error parsing cacerts.md");

typo: cacerts.fingerprints

   83         decomposer = new AlgorithmDecomposer();

Doesn't seem to be used, delete?

   92     public static boolean isAnchor(X509Certificate cert) {

A better name for this method might be contains().

CertificateParameters
---------------------

   37 public class CertificateParameters {

A better name might be CertConstraintParameters.

   43         this(X509CertImpl.toImpl(c), anchor);

It doesn't seem like you need to convert this to an X509CertImpl. In
DisabledAlgorithmConstraints, you just call methods on X509Certificate.

   46     public CertificateParameters(X509Certificate c) throws 
CertificateException {

Doesn't seem to be used; remove?

   50     public CertificateParameters(X509CertImpl c, boolean anchor) {

Make private, or just combine with other ctor as it really isn't needed.

   59     public boolean isTrustedChain() {

A better name might be "isAnchoredToCaCert".

   63     public X509CertImpl getCertificate() {

Change return type to X509Certificate.

AlgorithmChecker
----------------

   93     // True if trust anchor checking finds a match in the cacerts file
   94     private boolean trustedMatch = false;

This really means "true if the cacerts constraint enabled AND the chain 
is  anchored by a cacert". Can you add that to the comment so it is more 
clear? Maybe the variable name should be changed to 
"caCertConstraintApplies".

   97     private static final boolean checkerEnabled =
   98             certPathDefaultConstraints.checkProperty("cacerts");

Call this cacertsEnabled to be more specific?

  159     // Check if the 'cert' is in the trust anchor file (cacerts)
  160     private static boolean isAnchor(X509Certificate cert) {

Call this caCertConstraintApplies()?

  161         if (!checkerEnabled) {
  162             return false;
  163         }

I'm not sure I understand why

  165         if (debug != null) 
debug.println("AlgorithmChecker.isAnchor: " +

Suggest the following to improve readability:

     if (debug != null) {
         debug.println("AlgorithmChecker.isAnchor: " +
                       cert.getSigAlgName());
     }

DisabledAlgorithmConstraints
----------------------------

  62     private final String propertyName;

Doesn't seem to be used; delete?

  138     public final void permits(Set<CryptoPrimitive> primitives,
  139             X509Certificate cert) throws CertPathValidatorException {

Doesn't seem to be used; delete?

  246                     if (!constraintsMap.containsKey(algorithm)) {
  247                         constraintsMap.putIfAbsent(algorithm, new 
HashSet<>());
  248                     }

You can replace this with:

     constraintsMap.computeIfAbsent(algorithm, k -> new HashSet<>());

Same comment on lines 280-282.

251                 algorithm.toUpperCase(Locale.ENGLISH);

Shouldn't you also do this before adding it to the map on line 246-7?

  253                 if (debug != null) debug.println("Constraints len: " +
  254                         rComma.substring(space).split("&").length);

I suspect this debugging is more useful for debugging your own code. But 
we shouldn't include it unless it is helpful for analyzing
real issues, as the debug log files are long enough :) Same comment 
applies to other debugging statements (ex: lines 324-9).

287                     lastConstraint = c;

This seems like a bug since it is overwriting what was just done on line 
285. Should this be moved to right after line 283?

Also, if you had a constraint like: "RSA keySize < 1024, RSA keySize > 
4096" it looks like the 2nd RSA constraint will replace the first 
constraint, which isn't what I think is intended.

  293         public Set<Constraint> getConstraints(Key key) {

I think you can remove this method and just change line 304 to:

     Set<Constraint> set = getConstraints(key.getAlgorithm());

  393         public boolean permits(Key key) {
  403         public void permits(CertificateParameters cp) throws
CertPathValidatorException {

These should probably be abstract.

  416         CertConstraint(String algo, String s) {

Better name for "s"?

--Sean



More information about the security-dev mailing list