From 653df8acddbc0724bddaa6bdfb24cfb2fbc49ecb Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Thu, 13 Feb 2025 14:16:29 +0200 Subject: [PATCH] SDK: Add ca extension when issue CA certificates (#2277) Signed-off-by: Avgustin Marinov --- .../java/org/eclipse/hawkbit/sdk/ca/CA.java | 53 ++++++++++++------- .../sdk/mgmt/AuthenticationSetupHelper.java | 16 +++--- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/ca/CA.java b/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/ca/CA.java index 79b37000e..7bfd155d9 100644 --- a/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/ca/CA.java +++ b/hawkbit-sdk/hawkbit-sdk-commons/src/main/java/org/eclipse/hawkbit/sdk/ca/CA.java @@ -23,6 +23,10 @@ import java.util.Objects; import javax.security.auth.x500.X500Principal; import lombok.Data; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.X509Extension; +import org.bouncycastle.cert.CertIOException; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; @@ -70,24 +74,14 @@ public class CA { return issue(subject, null, null); } - // generate key and issue a certificate + // generate key and issue a CA certificate + public CA issueCA(final String subject, final Date notBefore, final Date notAfter) throws CertificateException { + return new CA(issue(subject, notBefore, notAfter, true)); + } + + // generate key and issue an end certificate public Certificate issue(final String subject, final Date notBefore, final Date notAfter) throws CertificateException { - Objects.requireNonNull(subject); - try { - final KeyPair keyPair = genKey(); - final X509Certificate[] certificateChain = certificate.getCertificateChain(); - final ContentSigner signer = new JcaContentSignerBuilder(SHA_256_WITH_RSA_ENCRYPTION).build(certificate.getKeyPair().getPrivate()); - final X509v3CertificateBuilder caCertBuilder = new JcaX509v3CertificateBuilder( - certificateChain[0].getSubjectX500Principal(), - BigInteger.valueOf(nextSerial++), notBefore(notBefore), notAfter(notAfter), new X500Principal(subject), - keyPair.getPublic()); - final X509Certificate[] subjectCertificateChain = new X509Certificate[certificateChain.length + 1]; - certificateChain[0] = new JcaX509CertificateConverter().getCertificate(caCertBuilder.build(signer)); - System.arraycopy(certificateChain, 0, subjectCertificateChain, 1, certificateChain.length); - return new Certificate(keyPair, subjectCertificateChain); - } catch (final NoSuchAlgorithmException | OperatorCreationException e) { - throw new CertificateException(e); - } + return issue(subject, notBefore, notAfter, false); } public String getFingerprint() { @@ -99,6 +93,28 @@ public class CA { } } + private Certificate issue(final String subject, final Date notBefore, final Date notAfter, final boolean ca) throws CertificateException { + Objects.requireNonNull(subject); + try { + final KeyPair keyPair = genKey(); + final X509Certificate[] certificateChain = certificate.getCertificateChain(); + final ContentSigner signer = new JcaContentSignerBuilder(SHA_256_WITH_RSA_ENCRYPTION).build(certificate.getKeyPair().getPrivate()); + final X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder( + certificateChain[0].getSubjectX500Principal(), + BigInteger.valueOf(nextSerial++), notBefore(notBefore), notAfter(notAfter), new X500Principal(subject), + keyPair.getPublic()); + if (ca) { + certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true)); + } + final X509Certificate[] subjectCertificateChain = new X509Certificate[certificateChain.length + 1]; + subjectCertificateChain[0] = new JcaX509CertificateConverter().getCertificate(certBuilder.build(signer)); + System.arraycopy(certificateChain, 0, subjectCertificateChain, 1, certificateChain.length); + return new Certificate(keyPair, subjectCertificateChain); + } catch (final NoSuchAlgorithmException | OperatorCreationException | CertIOException e) { + throw new CertificateException(e); + } + } + private static String toHex(final byte[] bytes) { final StringBuilder sb = new StringBuilder(); for (final byte b : bytes) { @@ -115,8 +131,9 @@ public class CA { final ContentSigner selfSigner = new JcaContentSignerBuilder(SHA_256_WITH_RSA_ENCRYPTION).build(keyPair.getPrivate()); final X509v3CertificateBuilder caCertBuilder = new JcaX509v3CertificateBuilder( caPrincipal, BigInteger.valueOf(0L), notBefore(notBefore), notAfter(notAfter), caPrincipal, keyPair.getPublic()); + caCertBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true)); return new Certificate(keyPair, new X509Certificate[] { new JcaX509CertificateConverter().getCertificate(caCertBuilder.build(selfSigner)) }); - } catch (final NoSuchAlgorithmException | OperatorCreationException e) { + } catch (final NoSuchAlgorithmException | OperatorCreationException | CertIOException e) { throw new CertificateException(e); } } diff --git a/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java b/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java index 5e2fffd7f..bdde9df40 100644 --- a/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java +++ b/hawkbit-sdk/hawkbit-sdk-mgmt/src/main/java/org/eclipse/hawkbit/sdk/mgmt/AuthenticationSetupHelper.java @@ -62,7 +62,7 @@ public class AuthenticationSetupHelper { CA ddiCA = tenant.getDdiCA(); if (ddiCA == null) { final CA ddiRootCA = new CA(); - ddiCA = new CA(ddiRootCA.issue(CA.DEFAULT_INTERMEDIATE_CA_DN, null, null)); + ddiCA = ddiRootCA.issueCA(CA.DEFAULT_INTERMEDIATE_CA_DN, null, null); tenant.setDdiCA(ddiCA); } if (!Boolean.TRUE.equals(Objects.requireNonNull(mgmtTenantManagementRestApi @@ -104,18 +104,16 @@ public class AuthenticationSetupHelper { .getBody()).getValue()))) { mgmtTenantManagementRestApi.updateTenantConfiguration(Map.of(AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, true)); } - if (!gatewayToken.equals( - Objects.requireNonNull(mgmtTenantManagementRestApi - .getTenantConfigurationValue(AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY) - .getBody()).getValue())) { + if (!gatewayToken.equals(Objects.requireNonNull(mgmtTenantManagementRestApi + .getTenantConfigurationValue(AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY) + .getBody()).getValue())) { mgmtTenantManagementRestApi.updateTenantConfiguration(Map.of(AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, gatewayToken)); } } - // if gateway token is configured then the gateway auth is enabled key is set - // so all devices use gateway token authentication - // otherwise target token authentication is enabled. Then all devices shall be registered - // and the target token shall be set to the one from the DDI controller instance + // if gateway token is configured then the gateway auth is enabled, so all devices use gateway token authentication. + // otherwise, target token authentication is enabled - then all devices shall be registered and the target token shall be set to the one from + // the DDI controller instance public void setupTargetAuthentication() { final String gatewayToken = tenant.getGatewayToken(); if (ObjectUtils.isEmpty(gatewayToken)) {