diff --git a/src/main/java/de/mlessmann/certassist/models/Certificate.java b/src/main/java/de/mlessmann/certassist/models/Certificate.java
index fdf3d16..6150139 100644
--- a/src/main/java/de/mlessmann/certassist/models/Certificate.java
+++ b/src/main/java/de/mlessmann/certassist/models/Certificate.java
@@ -3,12 +3,13 @@ package de.mlessmann.certassist.models;
import jakarta.persistence.*;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
+import lombok.*;
+import org.hibernate.proxy.HibernateProxy;
+
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
-import lombok.*;
-import org.hibernate.proxy.HibernateProxy;
@Entity
@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "fingerprint" }) })
@@ -29,14 +30,7 @@ public class Certificate {
private String trustingAuthority;
- /**
- *
- * - -1 = no requested key length is known (might happen with imported certificates)
- * - 0 = no key is available for this certificate (might happen with trusted third party certificates)
- * - > 1 = The key length in bits used for the private key of this certificate
- *
- */
- @Min(-1)
+ @Min(1)
private int requestedKeyLength;
private OffsetDateTime notBefore;
@@ -75,12 +69,8 @@ public class Certificate {
public final boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
- Class> oEffectiveClass = o instanceof HibernateProxy
- ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass()
- : o.getClass();
- Class> thisEffectiveClass = this instanceof HibernateProxy
- ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass()
- : this.getClass();
+ Class> oEffectiveClass = o instanceof HibernateProxy ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass() : o.getClass();
+ Class> thisEffectiveClass = this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass() : this.getClass();
if (thisEffectiveClass != oEffectiveClass) return false;
Certificate that = (Certificate) o;
return getId() != null && Objects.equals(getId(), that.getId());
@@ -88,8 +78,6 @@ public class Certificate {
@Override
public final int hashCode() {
- return this instanceof HibernateProxy
- ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode()
- : getClass().hashCode();
+ return this instanceof HibernateProxy ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode() : getClass().hashCode();
}
}
diff --git a/src/main/java/de/mlessmann/certassist/openssl/OpenSSLService.java b/src/main/java/de/mlessmann/certassist/openssl/OpenSSLService.java
index 85ae4b1..9355796 100644
--- a/src/main/java/de/mlessmann/certassist/openssl/OpenSSLService.java
+++ b/src/main/java/de/mlessmann/certassist/openssl/OpenSSLService.java
@@ -23,9 +23,11 @@ import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.security.cert.X509Certificate;
import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
+import java.time.temporal.IsoFields;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -70,20 +72,20 @@ public class OpenSSLService {
"^(?[0-9a-zA-Z]+) (?i)Fingerprint(?-i)=(?[a-z:A-Z0-9]+)"
);
private final DateTimeFormatter OSSL_DATE_TIME = new DateTimeFormatterBuilder()
- .parseCaseInsensitive()
- .appendValue(ChronoField.YEAR, 4)
- .appendLiteral('-')
- .appendValue(ChronoField.MONTH_OF_YEAR, 2)
- .appendLiteral('-')
- .appendValue(ChronoField.DAY_OF_MONTH, 2)
- .appendLiteral(' ')
- .appendValue(ChronoField.HOUR_OF_DAY, 2)
- .appendLiteral(':')
- .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
- .appendLiteral(':')
- .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
- .appendOffset("+HH:MM:ss", "Z")
- .toFormatter();
+ .parseCaseInsensitive()
+ .appendValue(ChronoField.YEAR, 4)
+ .appendLiteral('-')
+ .appendValue(ChronoField.MONTH_OF_YEAR, 2)
+ .appendLiteral('-')
+ .appendValue(ChronoField.DAY_OF_MONTH, 2)
+ .appendLiteral(' ')
+ .appendValue(ChronoField.HOUR_OF_DAY, 2)
+ .appendLiteral(':')
+ .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+ .appendLiteral(':')
+ .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+ .appendOffset("+HH:MM:ss","Z")
+ .toFormatter();
private static final String OSSL_ENV_KEY_PW = "KEY_PASS";
private static final String OSSL_ARG_KEY_PW = "env:" + OSSL_ENV_KEY_PW;
private final AtomicBoolean versionLogged = new AtomicBoolean(false);
@@ -762,7 +764,7 @@ public class OpenSSLService {
"sep_multiline",
"-nameopt",
"lname",
- "-modulus"
+ "-modulus"
)
);
command.addAll(Arrays.asList(additArgs));
diff --git a/src/main/java/de/mlessmann/certassist/openssl/X509CertificateInfo.java b/src/main/java/de/mlessmann/certassist/openssl/X509CertificateInfo.java
index d99d506..3f81078 100644
--- a/src/main/java/de/mlessmann/certassist/openssl/X509CertificateInfo.java
+++ b/src/main/java/de/mlessmann/certassist/openssl/X509CertificateInfo.java
@@ -2,21 +2,23 @@ package de.mlessmann.certassist.openssl;
import de.mlessmann.certassist.models.CertificateInfoExtension;
import de.mlessmann.certassist.models.CertificateInfoSubject;
-import java.time.OffsetDateTime;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
import lombok.Builder;
import org.springframework.lang.Nullable;
+import java.time.OffsetDateTime;
+import java.time.ZonedDateTime;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
@Builder
public record X509CertificateInfo(
- CertificateInfoSubject subject,
- @Nullable CertificateInfoSubject issuer,
- String serial,
- OffsetDateTime notBefore,
- OffsetDateTime notAfter,
- List extensions
+ CertificateInfoSubject subject,
+ @Nullable CertificateInfoSubject issuer,
+ String serial,
+ OffsetDateTime notBefore,
+ OffsetDateTime notAfter,
+ List extensions
) {
public X509CertificateInfo {
Objects.requireNonNull(subject);
@@ -32,8 +34,4 @@ public record X509CertificateInfo(
}
return Collections.unmodifiableList(extensions);
}
-
- public boolean hasExtensions() {
- return extensions != null && !extensions.isEmpty();
- }
}
diff --git a/src/main/java/de/mlessmann/certassist/service/CertificateCreationService.java b/src/main/java/de/mlessmann/certassist/service/CertificateCreationService.java
index 349558a..1383116 100644
--- a/src/main/java/de/mlessmann/certassist/service/CertificateCreationService.java
+++ b/src/main/java/de/mlessmann/certassist/service/CertificateCreationService.java
@@ -79,17 +79,9 @@ public class CertificateCreationService {
private Certificate createEntityFromInfo(X509CertificateInfo info) {
final Certificate certificate = new Certificate();
- certificate.setType(
- mapCertificateRequestType(
- info.issuer() != null
- ? CertificateInfo.RequestType.NORMAL_CERTIFICATE
- : CertificateInfo.RequestType.STANDALONE_CERTIFICATE
- )
- );
+ certificate.setType(mapCertificateRequestType(info.issuer() != null ? CertificateInfo.RequestType.NORMAL_CERTIFICATE : CertificateInfo.RequestType.STANDALONE_CERTIFICATE));
certificate.setSubjectCommonName(info.subject().getCommonName());
- if (info.issuer() != null) {
- certificate.setTrustingAuthority(info.issuer().getCommonName());
- }
+ certificate.setTrustingAuthority(info.issuer().getCommonName());
certificate.setRequestedKeyLength(-1);
certificate.setNotBefore(info.notBefore());
certificate.setNotAfter(info.notAfter());
@@ -102,14 +94,12 @@ public class CertificateCreationService {
certificate.setSubjectState(subjectInfo.getState());
certificate.setSubjectLocality(subjectInfo.getLocality());
- if (info.hasExtensions()) {
- final CertificateInfoExtension extension = info.extensions().getFirst();
- if (extension != null) {
- final CertificateExtension certificateExtension = new CertificateExtension();
- certificateExtension.setIdentifier("alternativeNames");
- certificateExtension.setValue(String.join(",", extension.getAlternativeDnsNames()));
- certificate.setCertificateExtension(List.of(certificateExtension));
- }
+ final CertificateInfoExtension extension = info.extensions().getFirst();
+ if (extension != null) {
+ final CertificateExtension certificateExtension = new CertificateExtension();
+ certificateExtension.setIdentifier("alternativeNames");
+ certificateExtension.setValue(String.join(",", extension.getAlternativeDnsNames()));
+ certificate.setCertificateExtension(List.of(certificateExtension));
}
return certificate;
}
@@ -123,7 +113,6 @@ public class CertificateCreationService {
try {
String fingerprint = openSSLService.getCertificateFingerprint(certificate);
Certificate entity = createEntityFromInfo(openSSLService.getCertificateInfo(certificate));
- entity.setRequestedKeyLength(-1);
entity.setFingerprint(fingerprint);
entity.setCert(Files.readAllBytes(certificate));
if (keyFile != null) {
diff --git a/src/test/java/de/mlessmann/certassist/TestOpenSSLService.java b/src/test/java/de/mlessmann/certassist/TestOpenSSLService.java
index cc6c4ea..c25780f 100644
--- a/src/test/java/de/mlessmann/certassist/TestOpenSSLService.java
+++ b/src/test/java/de/mlessmann/certassist/TestOpenSSLService.java
@@ -1,9 +1,5 @@
package de.mlessmann.certassist;
-import static java.util.Objects.requireNonNull;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.*;
-
import de.mlessmann.certassist.models.CertificateInfo;
import de.mlessmann.certassist.models.CertificateInfo.RequestType;
import de.mlessmann.certassist.models.CertificateInfoExtension;
@@ -12,19 +8,24 @@ import de.mlessmann.certassist.openssl.CertificatePasswordProvider;
import de.mlessmann.certassist.openssl.CertificateProvider;
import de.mlessmann.certassist.openssl.OpenSSLService;
import de.mlessmann.certassist.service.ExecutableResolver;
-import java.nio.file.Path;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
+import java.nio.file.Path;
+
+import static java.util.Objects.requireNonNull;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
@SpringBootTest
class TestOpenSSLService {
public static final String TEST_CERT_PASSPHRASE = "ABC-123";
public static final Path TEST_CERT_PATH = Path.of("src/test/resources/openssl");
public static final String TEST_CERT_FINGERPRINT =
- "SHA1;4E:D6:0A:47:F0:63:AD:96:26:83:16:28:32:F5:E8:36:5A:62:91:95";
+ "SHA1;4E:D6:0A:47:F0:63:AD:96:26:83:16:28:32:F5:E8:36:5A:62:91:95";
private static final String ERR_NOT_ENCRYPTED = "Private key not encrypted";
private static final String ERR_VERIFY_FAILED = "Certificate verification failed";
@@ -44,55 +45,57 @@ class TestOpenSSLService {
var certificateCreator = new OpenSSLService(executableResolver, passwordProvider, certificateProvider);
CertificateInfo certRequest = CertificateInfo
- .builder()
- .type(RequestType.STANDALONE_CERTIFICATE)
- .subject(
- CertificateInfoSubject
- .builder()
- .commonName("test.home")
- .country("DE")
- .state("SH")
- .locality("HH")
- .organization("Crazy-Cats")
- )
- .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.home", "test3.home"))
- .build();
+ .builder()
+ .type(RequestType.STANDALONE_CERTIFICATE)
+ .subject(
+ CertificateInfoSubject
+ .builder()
+ .commonName("test.home")
+ .country("DE")
+ .state("SH")
+ .locality("HH")
+ .organization("Crazy-Cats")
+ )
+ .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.home", "test3.home"))
+ .build();
try (var cert = certificateCreator.createCertificate(certRequest)) {
assertThat(certificateCreator.verifyCertificate(cert.certificatePath(), cert.certificatePath()))
- .withFailMessage(ERR_VERIFY_FAILED)
- .isTrue();
+ .withFailMessage(ERR_VERIFY_FAILED)
+ .isTrue();
assertThat(certificateCreator.isKeyEncrypted(requireNonNull(cert.certificateKeyPath())))
- .withFailMessage(ERR_NOT_ENCRYPTED)
- .isTrue();
+ .withFailMessage(ERR_NOT_ENCRYPTED)
+ .isTrue();
CertificateInfo childRequest = CertificateInfo
- .builder()
- .type(RequestType.NORMAL_CERTIFICATE)
- .trustingAuthority(cert.fingerprint())
- .subject(
- CertificateInfoSubject
- .builder()
- .commonName("test.local")
- .country("DE")
- .state("SH")
- .locality("HH")
- .organization("Crazy-Cats")
- )
- .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.local", "test3.local"))
- .build();
+ .builder()
+ .type(RequestType.NORMAL_CERTIFICATE)
+ .trustingAuthority(cert.fingerprint())
+ .subject(
+ CertificateInfoSubject
+ .builder()
+ .commonName("test.local")
+ .country("DE")
+ .state("SH")
+ .locality("HH")
+ .organization("Crazy-Cats")
+ )
+ .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.local", "test3.local"))
+ .build();
var spiedCert = spy(cert);
doNothing().when(spiedCert).close();
when(certificateProvider.requestCertificateUsage(cert.fingerprint())).thenReturn(spiedCert);
try (var childCert = certificateCreator.createCertificate(childRequest)) {
Path fullchain = childCert.fullchainPath();
- assertThat(certificateCreator.verifyCertificate(requireNonNull(fullchain), cert.certificatePath()))
- .withFailMessage(ERR_VERIFY_FAILED)
- .isTrue();
+ assertThat(
+ certificateCreator.verifyCertificate(requireNonNull(fullchain), cert.certificatePath())
+ )
+ .withFailMessage(ERR_VERIFY_FAILED)
+ .isTrue();
assertThat(certificateCreator.isKeyEncrypted(requireNonNull(childCert.certificateKeyPath())))
- .withFailMessage(ERR_NOT_ENCRYPTED)
- .isTrue();
+ .withFailMessage(ERR_NOT_ENCRYPTED)
+ .isTrue();
}
}
}
@@ -121,7 +124,6 @@ class TestOpenSSLService {
assertThat(request.subject().getState()).isEqualTo("SH");
assertThat(request.subject().getLocality()).isEqualTo("HH");
assertThat(request.subject().getOrganization()).isEqualTo("Crazy-Cats");
- assertThat(request.extensions().getFirst().getAlternativeDnsNames())
- .containsExactly("test2.local", "test3.local");
+ assertThat(request.extensions().getFirst().getAlternativeDnsNames()).containsExactly("test2.local", "test3.local");
}
}
diff --git a/src/test/java/de/mlessmann/certassist/repositories/CertificateRepositoryTest.java b/src/test/java/de/mlessmann/certassist/repositories/CertificateRepositoryTest.java
index 1b53594..e142fa4 100644
--- a/src/test/java/de/mlessmann/certassist/repositories/CertificateRepositoryTest.java
+++ b/src/test/java/de/mlessmann/certassist/repositories/CertificateRepositoryTest.java
@@ -6,6 +6,7 @@ import de.mlessmann.certassist.models.Certificate;
import de.mlessmann.certassist.models.CertificateExtension;
import de.mlessmann.certassist.models.CertificateType;
import jakarta.transaction.Transactional;
+
import java.time.OffsetDateTime;
import java.util.List;
import java.util.stream.StreamSupport;