HDDS-5071. Fix duration of sub-ca certs. (#2127)

diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
index d5cdcc7..5552fdc 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java
@@ -140,7 +140,8 @@
       "hdds.block.token.expiry.time";
   public static final String HDDS_BLOCK_TOKEN_EXPIRY_TIME_DEFAULT = "1d";
   /**
-   * Maximum duration of certificates issued by SCM including Self-Signed Roots.
+   * Maximum duration of certificates issued by SCM including Self-Signed
+   * Roots and sub-ca certificates issued by root CA.
    * The formats accepted are based on the ISO-8601 duration format PnDTnHnMn.nS
    * Default value is 5 years and written as P1865D.
    */
diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java
index 394a0c3..61c58da 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java
@@ -90,7 +90,7 @@
   private final String keyDir;
   private final String privateKeyFileName;
   private final String publicKeyFileName;
-  private final Duration certDuration;
+  private final Duration maxCertDuration;
   private final String x509SignatureAlgo;
   private final boolean blockTokenEnabled;
   private final String certificateDir;
@@ -130,7 +130,7 @@
 
     String durationString = this.configuration.get(HDDS_X509_MAX_DURATION,
         HDDS_X509_MAX_DURATION_DEFAULT);
-    this.certDuration = Duration.parse(durationString);
+    this.maxCertDuration = Duration.parse(durationString);
     this.x509SignatureAlgo = this.configuration.get(HDDS_X509_SIGNATURE_ALGO,
         HDDS_X509_SIGNATURE_ALGO_DEFAULT);
     this.certificateDir = this.configuration.get(HDDS_X509_DIR_NAME,
@@ -159,6 +159,13 @@
             HDDS_X509_DEFAULT_DURATION_DEFAULT);
     defaultCertDuration = Duration.parse(certDurationString);
 
+    if (maxCertDuration.compareTo(defaultCertDuration) < 0) {
+      LOG.error("Certificate duration {} should not be greater than Maximum " +
+          "Certificate duration {}", maxCertDuration, defaultCertDuration);
+      throw new IllegalArgumentException("Certificate duration should not be " +
+          "greater than maximum Certificate duration");
+    }
+
     this.crlName = this.configuration.get(HDDS_X509_CRL_NAME,
                                           HDDS_X509_CRL_NAME_DEFAULT);
 
@@ -320,7 +327,7 @@
    * @return Duration.
    */
   public Duration getMaxCertificateDuration() {
-    return this.certDuration;
+    return this.maxCertDuration;
   }
 
   public boolean isBlockTokenEnabled() {
diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index 52e6241..ee18441 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -1858,8 +1858,9 @@
     <value>P1865D</value>
     <tag>OZONE, HDDS, SECURITY</tag>
     <description>Max time for which certificate issued by SCM CA are valid.
-      . The formats accepted are based on the ISO-8601 duration format
-      PnDTnHnMn.nS</description>
+      This duration is used for self-signed root cert and scm sub-ca certs
+      issued by root ca. The formats accepted are based on the ISO-8601
+      duration format PnDTnHnMn.nS</description>
   </property>
   <property>
     <name>hdds.x509.signature.algorithm</name>
diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java
index 7622dda..7a83509 100644
--- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java
+++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java
@@ -214,8 +214,15 @@
       CertificateApprover.ApprovalType approverType, NodeType role) {
     LocalDate beginDate = LocalDate.now().atStartOfDay().toLocalDate();
     LocalDateTime temp = LocalDateTime.of(beginDate, LocalTime.MIDNIGHT);
-    LocalDate endDate =
-        temp.plus(config.getDefaultCertDuration()).toLocalDate();
+
+    LocalDate endDate;
+    // When issuing certificates for sub-ca use the max certificate duration
+    // similar to self signed root certificate.
+    if (role == NodeType.SCM) {
+      endDate = temp.plus(config.getMaxCertificateDuration()).toLocalDate();
+    } else {
+      endDate = temp.plus(config.getDefaultCertDuration()).toLocalDate();
+    }
 
     CompletableFuture<X509CertificateHolder> xcertHolder =
         approver.inspectCSR(csr);
diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java
index f5a2d8c..7e68aeb 100644
--- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java
+++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java
@@ -20,6 +20,7 @@
 package org.apache.hadoop.hdds.security.x509.certificate.authority;
 
 import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.hadoop.hdds.HddsConfigKeys;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
 import org.apache.hadoop.hdds.security.x509.SecurityConfig;
@@ -49,6 +50,8 @@
 import java.security.NoSuchProviderException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.time.LocalDate;
+import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
@@ -345,6 +348,8 @@
   @Test
   public void testIntermediaryCA() throws Exception {
 
+    conf.set(HddsConfigKeys.HDDS_X509_MAX_DURATION, "P3650D");
+
     String clusterId = RandomStringUtils.randomAlphanumeric(4);
     String scmId = RandomStringUtils.randomAlphanumeric(4);
 
@@ -378,7 +383,12 @@
     Assert.assertTrue(holder.isDone());
 
     X509CertificateHolder certificateHolder = holder.get();
+
+
     Assert.assertNotNull(certificateHolder);
+    Assert.assertEquals(10, certificateHolder.getNotAfter().toInstant()
+        .atZone(ZoneId.systemDefault())
+        .toLocalDate().compareTo(LocalDate.now()));
 
     X509CertificateHolder rootCertHolder = rootCA.getCACertificate();