Skip to content

Commit a7bc371

Browse files
committed
HDDS-13781. Certificate expiry date should consider time zone daylight saving impact
1 parent d5be986 commit a7bc371

File tree

2 files changed

+72
-10
lines changed

2 files changed

+72
-10
lines changed

hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
import java.security.cert.CertPath;
3535
import java.security.cert.CertificateException;
3636
import java.security.cert.X509Certificate;
37+
import java.time.Duration;
3738
import java.time.LocalDateTime;
3839
import java.time.ZoneId;
40+
import java.time.ZonedDateTime;
3941
import java.util.Date;
4042
import java.util.List;
4143
import java.util.concurrent.CompletableFuture;
@@ -206,7 +208,7 @@ public Future<CertPath> requestCertificate(
206208
CertificateApprover.ApprovalType approverType, NodeType role,
207209
String certSerialId) {
208210
LocalDateTime beginDate = LocalDateTime.now();
209-
LocalDateTime endDate = expiryFor(beginDate, role);
211+
Duration certDuration = getDuration(beginDate, role);
210212

211213
CompletableFuture<Void> csrInspection = approver.inspectCSR(csr);
212214
CompletableFuture<CertPath> certPathPromise = new CompletableFuture<>();
@@ -224,7 +226,7 @@ public Future<CertPath> requestCertificate(
224226
break;
225227
case KERBEROS_TRUSTED:
226228
case TESTING_AUTOMATIC:
227-
X509Certificate signedCertificate = signAndStoreCertificate(beginDate, endDate, csr, role, certSerialId);
229+
X509Certificate signedCertificate = signAndStoreCertificate(beginDate, certDuration, csr, role, certSerialId);
228230
CertificateCodec codec = new CertificateCodec(config, componentName);
229231
CertPath certPath = codec.getCertPath();
230232
CertPath updatedCertPath = codec.prependCertToCertPath(signedCertificate, certPath);
@@ -240,18 +242,21 @@ public Future<CertPath> requestCertificate(
240242
return certPathPromise;
241243
}
242244

243-
private LocalDateTime expiryFor(LocalDateTime beginDate, NodeType role) {
245+
private Duration getDuration(LocalDateTime beginDate, NodeType role) {
244246
// When issuing certificates for sub-ca use the max certificate duration similar to self-signed root certificate.
245247
if (role == NodeType.SCM) {
246-
return beginDate.plus(config.getMaxCertificateDuration());
248+
return config.getMaxCertificateDuration();
247249
}
248-
return beginDate.plus(config.getDefaultCertDuration());
250+
return config.getDefaultCertDuration();
249251
}
250252

251253
private X509Certificate signAndStoreCertificate(
252-
LocalDateTime beginDate, LocalDateTime endDate, PKCS10CertificationRequest csr, NodeType role, String certSerialId
254+
LocalDateTime beginDate, Duration duration, PKCS10CertificationRequest csr, NodeType role, String certSerialId
253255
) throws IOException, OperatorCreationException, CertificateException {
254256

257+
ZoneId zoneId = ZoneId.systemDefault();
258+
ZonedDateTime endDate = beginDate.atZone(zoneId).plus(duration);
259+
255260
lock.lock();
256261
X509Certificate xcert;
257262
try {
@@ -260,7 +265,7 @@ private X509Certificate signAndStoreCertificate(
260265
getPrivateKey(),
261266
getCACertificate(),
262267
Date.from(beginDate.atZone(ZoneId.systemDefault()).toInstant()),
263-
Date.from(endDate.atZone(ZoneId.systemDefault()).toInstant()),
268+
Date.from(endDate.toInstant()),
264269
csr, scmID, clusterID, certSerialId);
265270
if (store != null) {
266271
store.checkValidCertID(xcert.getSerialNumber());
@@ -487,14 +492,14 @@ private void generateRootCertificate(
487492
throws IOException, SCMSecurityException {
488493
Preconditions.checkNotNull(this.config);
489494
LocalDateTime beginDate = LocalDateTime.now();
490-
LocalDateTime endDate =
491-
beginDate.plus(securityConfig.getMaxCertificateDuration());
495+
ZoneId zoneId = ZoneId.systemDefault();
496+
ZonedDateTime endDate = beginDate.atZone(zoneId).plus(securityConfig.getMaxCertificateDuration());
492497
SelfSignedCertificate.Builder builder = SelfSignedCertificate.newBuilder()
493498
.setSubject(this.subject)
494499
.setScmID(this.scmID)
495500
.setClusterID(this.clusterID)
496501
.setBeginDate(beginDate)
497-
.setEndDate(endDate)
502+
.setEndDate(endDate.toLocalDateTime())
498503
.makeCA(rootCertificateId)
499504
.setConfiguration(securityConfig)
500505
.setKey(key);

hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@
4646
import java.time.LocalDate;
4747
import java.time.LocalDateTime;
4848
import java.time.ZoneId;
49+
import java.util.Date;
4950
import java.util.List;
51+
import java.util.TimeZone;
5052
import java.util.UUID;
5153
import java.util.concurrent.ExecutionException;
5254
import java.util.concurrent.Future;
@@ -450,6 +452,61 @@ clusterId, scmId, caStore, new DefaultProfile(),
450452
}
451453
}
452454

455+
@Test
456+
public void testDaylightSavingZone() throws Exception {
457+
TimeZone defaultTimeZone = TimeZone.getDefault();
458+
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
459+
460+
String scmId = RandomStringUtils.secure().nextAlphabetic(4);
461+
String clusterId = RandomStringUtils.secure().nextAlphabetic(4);
462+
KeyPair keyPair =
463+
new HDDSKeyGenerator(securityConfig).generateKey();
464+
//TODO: generateCSR!
465+
PKCS10CertificationRequest csr = new CertificateSignRequest.Builder()
466+
.addDnsName("hadoop.apache.org")
467+
.addIpAddress("8.8.8.8")
468+
.addServiceName("OzoneMarketingCluster002")
469+
.setCA(false)
470+
.setClusterID(clusterId)
471+
.setScmID(scmId)
472+
.setSubject("Ozone Cluster")
473+
.setConfiguration(securityConfig)
474+
.setKey(keyPair)
475+
.build()
476+
.generateCSR();
477+
478+
CertificateServer testCA = new DefaultCAServer("testCA",
479+
clusterId, scmId, caStore,
480+
new DefaultProfile(),
481+
Paths.get(SCM_CA_CERT_STORAGE_DIR, SCM_CA_PATH).toString());
482+
testCA.init(securityConfig, CAType.ROOT);
483+
484+
Future<CertPath> holder = testCA.requestCertificate(
485+
csr, CertificateApprover.ApprovalType.TESTING_AUTOMATIC, SCM,
486+
String.valueOf(System.nanoTime()));
487+
// Right now our calls are synchronous. Eventually this will have to wait.
488+
assertTrue(holder.isDone());
489+
//Test that the cert path returned contains the CA certificate in proper
490+
// place
491+
List<? extends Certificate> certBundle = holder.get().getCertificates();
492+
493+
// verify new created SCM certificate
494+
X509Certificate certificate = (X509Certificate) certBundle.get(0);
495+
Date startDate = certificate.getNotBefore();
496+
Date endDate = certificate.getNotAfter();
497+
assertEquals(securityConfig.getMaxCertificateDuration().toMillis(),
498+
endDate.toInstant().toEpochMilli() - startDate.toInstant().toEpochMilli());
499+
500+
// verify root CA
501+
List<? extends Certificate> certificateList = testCA.getCaCertPath().getCertificates();
502+
certificate = (X509Certificate) certificateList.get(0);
503+
startDate = certificate.getNotBefore();
504+
endDate = certificate.getNotAfter();
505+
assertEquals(securityConfig.getMaxCertificateDuration().toMillis(),
506+
endDate.toInstant().toEpochMilli() - startDate.toInstant().toEpochMilli());
507+
TimeZone.setDefault(defaultTimeZone);
508+
}
509+
453510
private X509Certificate generateExternalCert(KeyPair keyPair) throws Exception {
454511
LocalDateTime notBefore = LocalDateTime.now();
455512
LocalDateTime notAfter = notBefore.plusYears(1);

0 commit comments

Comments
 (0)