Search code examples
javax509certificatebouncycastle

Validate names against Name Constraints extension of a X509Certificate CA


I have a CA Certificate parsed as X509Certificate object which may or may not have Name Constraints extension.

Before I sign a new certificate using this CA certificate, I want to manually verify that given a hostname or IP address will be allowed by the CA. How can I accomplish this?


Solution

  • Even though I could see the JDK has decent APIs for this, they are all internal. So I ended up using Bouncy Castle.

      public boolean validateAgainstNamingConstraints(X509Certificate certificate, GeneralName name) {
        NameConstraints nameConstraints = null;
        try {
          nameConstraints = NameConstraints.getInstance(
              JcaX509ExtensionUtils.parseExtensionValue(certificate.getExtensionValue(Extension.nameConstraints.getId())));
        } catch (IOException e) {
          log.warn("Failed to parse name constraint. Skipping validation. {}", e.getMessage());
          return true;
        }
    
        if (nameConstraints == null) {
          return true;
        }
    
        var nameConstraintValidator = new PKIXNameConstraintValidator();
        if (nameConstraints.getPermittedSubtrees() != null) {
          nameConstraintValidator.intersectPermittedSubtree(nameConstraints.getPermittedSubtrees());
        }
    
        if (nameConstraints.getExcludedSubtrees() != null) {
          for (int i = 0; i < nameConstraints.getExcludedSubtrees().length; i++) {
            nameConstraintValidator.addExcludedSubtree(nameConstraints.getExcludedSubtrees()[i]);
          }
        }
    
        try {
          nameConstraintValidator.checkPermitted(name);
          nameConstraintValidator.checkExcluded(name);
          return true;
        } catch (NameConstraintValidatorException e) {
          return false;
        }
      }
    

    How to use:

    validateAgainstNamingConstraints(certificate, new GeneralName(GeneralName.dNSName, "test.google.com"))
    validateAgainstNamingConstraints(certificate, new GeneralName(GeneralName.iPAddress, "192.168.111.1"))