Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<module name="org.jboss.logging"/>
<module name="org.jboss.vfs"/>
<module name="org.jboss.logmanager"/>
<module name="org.jboss.threads"/>
<module name="org.wildfly.common"/>
<module name="org.wildfly.security.elytron-private"/>
</dependencies>
Expand Down
2 changes: 1 addition & 1 deletion elytron/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@
<exclude>legacy*.xml</exclude>
<exclude>elytron-subsystem-community*.xml</exclude>
</excludes>
<systemId>src/main/resources/schema/wildfly-elytron_18_0.xsd</systemId>
<systemId>src/main/resources/schema/wildfly-elytron_19_0.xsd</systemId>
</validationSet>
<validationSet>
<dir>src/main/resources/schema</dir>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.jboss.as.controller.ObjectTypeAttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.ResourceDefinition;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
Expand Down Expand Up @@ -430,7 +431,7 @@ protected void executeRuntimeStep(final OperationContext context, final ModelNod
File resolvedPath = ((KeyStoreService) keyStoreService).getResolvedPath(pathResolver, path, relativeTo);
boolean trustCacerts = TRUST_CACERTS.resolveModelAttribute(context, operation).asBoolean();
boolean validate = VALIDATE.resolveModelAttribute(context, operation).asBoolean();

final ModelNode expirationWatermarkModelAttribute = KeyStoreDefinition.EXPIRATION_WATERMARK.resolveModelAttribute(context, context.readResource(PathAddress.EMPTY_ADDRESS).getModel());
try {
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
Expand Down Expand Up @@ -480,7 +481,7 @@ protected void executeRuntimeStep(final OperationContext context, final ModelNod
final X509Certificate lastCertificate = certificateChain[certificateChain.length - 1];
final X509Certificate certificateOrIssuer = getCertificateOrIssuerFromKeyStores(lastCertificate, keyStore, getCacertsKeyStore(trustCacerts));
if (certificateOrIssuer == null) {
writeCertificate(context.getResult().get(ElytronDescriptionConstants.CERTIFICATE), lastCertificate);
writeCertificate(context.getResult().get(ElytronDescriptionConstants.CERTIFICATE), lastCertificate, context.getStability(), expirationWatermarkModelAttribute.asLong());
throw ROOT_LOGGER.topMostCertificateFromCertificateReplyNotTrusted();
}
if (! lastCertificate.equals(certificateOrIssuer)) {
Expand Down Expand Up @@ -514,14 +515,14 @@ protected void executeRuntimeStep(final OperationContext context, final ModelNod
throw ROOT_LOGGER.trustedCertificateAlreadyInCacertsKeyStore(trustedCertificateAlias);
}
}
writeCertificate(context.getResult().get(ElytronDescriptionConstants.CERTIFICATE), trustedCertificate, true);
writeCertificate(context.getResult().get(ElytronDescriptionConstants.CERTIFICATE), trustedCertificate, true, context.getStability(), expirationWatermarkModelAttribute.asLong());
throw ROOT_LOGGER.unableToDetermineIfCertificateIsTrusted();
} else {
try {
final HashMap<Principal, HashSet<X509Certificate>> certificatesMap = getKeyStoreCertificates(keyStore, cacertsKeyStore);
X500.createX509CertificateChain(trustedCertificate, certificatesMap);
} catch (IllegalArgumentException e) {
writeCertificate(context.getResult().get(ElytronDescriptionConstants.CERTIFICATE), trustedCertificate, true);
writeCertificate(context.getResult().get(ElytronDescriptionConstants.CERTIFICATE), trustedCertificate, true, context.getStability(), expirationWatermarkModelAttribute.asLong());
throw ROOT_LOGGER.unableToDetermineIfCertificateIsTrusted();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.jboss.as.controller.ObjectTypeAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.version.Stability;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;
import org.wildfly.common.iteration.ByteIterator;
Expand Down Expand Up @@ -88,9 +89,15 @@ class CertificateChainAttributeDefinitions {

// TODO - Consider adding some of the more detailed fields from X509Certificate

// derivative attributes
private static final SimpleAttributeDefinition VALIDITY = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.VALIDITY, ModelType.STRING)
.setRequired(false)
.setStability(Stability.COMMUNITY)
.build();

static final ObjectTypeAttributeDefinition CERTIFICATE = new ObjectTypeAttributeDefinition.Builder(ElytronDescriptionConstants.CERTIFICATE,
TYPE, ALGORITHM, FORMAT, PUBLIC_KEY, SHA_1_DIGEST, SHA_256_DIGEST, ENCODED,
SUBJECT, ISSUER, NOT_BEFORE, NOT_AFTER, SERIAL_NUMBER, SIGNATURE_ALGORITHM, SIGNATURE, VERSION)
SUBJECT, ISSUER, NOT_BEFORE, NOT_AFTER, SERIAL_NUMBER, SIGNATURE_ALGORITHM, SIGNATURE, VERSION, VALIDITY)
.setStorageRuntime()
.build();

Expand All @@ -101,11 +108,11 @@ static ObjectListAttributeDefinition getNamedCertificateList(final String name)
.build();
}

static void writeCertificate(final ModelNode certificateModel, final Certificate certificate) throws CertificateEncodingException, NoSuchAlgorithmException {
writeCertificate(certificateModel, certificate, true);
static void writeCertificate(final ModelNode certificateModel, final Certificate certificate, final Stability stability, final long expirationWarningWaterMark) throws CertificateEncodingException, NoSuchAlgorithmException {
writeCertificate(certificateModel, certificate, true, stability, expirationWarningWaterMark);
}

static void writeCertificate(final ModelNode certificateModel, final Certificate certificate, final boolean verbose) throws CertificateEncodingException, NoSuchAlgorithmException {
static void writeCertificate(final ModelNode certificateModel, final Certificate certificate, final boolean verbose, final Stability stability, final long expirationWarningWaterMark) throws CertificateEncodingException, NoSuchAlgorithmException {
certificateModel.get(ElytronDescriptionConstants.TYPE).set(certificate.getType());

PublicKey publicKey = certificate.getPublicKey();
Expand All @@ -123,11 +130,11 @@ static void writeCertificate(final ModelNode certificateModel, final Certificate
}

if (certificate instanceof X509Certificate) {
writeX509Certificate(certificateModel, (X509Certificate) certificate);
writeX509Certificate(certificateModel, (X509Certificate) certificate, stability, expirationWarningWaterMark);
}
}

private static void writeX509Certificate(final ModelNode certificateModel, final X509Certificate certificate) throws CertificateEncodingException, NoSuchAlgorithmException {
private static void writeX509Certificate(final ModelNode certificateModel, final X509Certificate certificate, final Stability stability, final long expirationWarningWaterMark) throws CertificateEncodingException, NoSuchAlgorithmException {
SimpleDateFormat sdf = new SimpleDateFormat(ISO_8601_FORMAT);

certificateModel.get(ElytronDescriptionConstants.SUBJECT).set(certificate.getSubjectX500Principal().getName());
Expand All @@ -138,6 +145,10 @@ private static void writeX509Certificate(final ModelNode certificateModel, final
certificateModel.get(ElytronDescriptionConstants.SIGNATURE_ALGORITHM).set(certificate.getSigAlgName());
certificateModel.get(ElytronDescriptionConstants.SIGNATURE).set(encodedHexString(certificate.getSignature()));
certificateModel.get(ElytronDescriptionConstants.VERSION).set("v" + certificate.getVersion());
//artificial parameters here, after concrete?
if(stability.enables(Stability.COMMUNITY)) {
certificateModel.get(ElytronDescriptionConstants.VALIDITY).set(CertificateValidity.getValidity(certificate.getNotBefore(), certificate.getNotAfter(), expirationWarningWaterMark).toString());
}
}

/**
Expand All @@ -148,8 +159,23 @@ private static void writeX509Certificate(final ModelNode certificateModel, final
* @throws CertificateEncodingException
* @throws NoSuchAlgorithmException
*/
static void writeCertificates(final ModelNode result, final Certificate[] certificates) throws CertificateEncodingException, NoSuchAlgorithmException {
writeCertificates(result, certificates, true);
static void writeCertificates(final ModelNode result, final Certificate[] certificates, final Stability stability) throws CertificateEncodingException, NoSuchAlgorithmException {
writeCertificates(result, certificates, true, stability, KeyStoreDefinition.EXPIRATION_WATERMARK.getDefaultValue().asLong());
}


/**
* Populate the supplied response with the model representation of the certificates.
*
* @param result the response to populate.
* @param certificates the certificates to add to the response.
* @param stability of operation context. Can be null in case its not part of model operations.
* @param expiratioWatermark threshold for expiration warning.
* @throws CertificateEncodingException
* @throws NoSuchAlgorithmException
*/
static void writeCertificates(final ModelNode result, final Certificate[] certificates, final Stability stability, final long expiratioWatermark) throws CertificateEncodingException, NoSuchAlgorithmException {
writeCertificates(result, certificates, true, stability, expiratioWatermark);
}

/**
Expand All @@ -158,14 +184,16 @@ static void writeCertificates(final ModelNode result, final Certificate[] certif
* @param result the response to populate.
* @param certificates the certificates to add to the response.
* @param verbose mode of output.
* @param stability of operation context. Can be null in case its not part of model operations.
* @param expiratioWatermark threshold for expiration warning.
* @throws CertificateEncodingException
* @throws NoSuchAlgorithmException
*/
static void writeCertificates(final ModelNode result, final Certificate[] certificates, final boolean verbose) throws CertificateEncodingException, NoSuchAlgorithmException {
static void writeCertificates(final ModelNode result, final Certificate[] certificates, final boolean verbose, final Stability stability, final long expirationWarningWaterMark) throws CertificateEncodingException, NoSuchAlgorithmException {
if (certificates != null) {
for (Certificate current : certificates) {
ModelNode certificate = new ModelNode();
writeCertificate(certificate, current, verbose);
writeCertificate(certificate, current, verbose, stability, expirationWarningWaterMark);
result.add(certificate);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.wildfly.extension.elytron;

import java.util.Calendar;
import java.util.Date;

enum CertificateValidity {
NOT_YET("not yet"), VALID("valid"), ABOUT_TO_EXPIRE("about to expire"), EXPIRED("EXPIRED");

private String token;

CertificateValidity(String string) {
this.token = string;
}

/*
* (non-Javadoc)
*
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return token;
}

/**
* Fetch representation of health based on provided factors.
* @param notBefore - certificate start date
* @param notAfter - certificate expiration date
* @param expirationWaterMark - watermark expressed in minutes.
* @return
* <ul>
* <li>{@linkplain #NOT_YET} - if currentDate.before(notBefore)</li>
* <li>{@linkplain #EXPIRE} - if currentDate.after(notAfter)</li>
* <li>{@linkplain #ABOUT_TO_EXPIRE} - if (currentDate+waterMark).after(notAfter)</li>
* <li>{@linkplain #VALID} - otherwise</li>
* </ul>
*/
static CertificateValidity getValidity(final Date notBefore, final Date notAfter, final long expirationWaterMark) {
final Date currentDate = Calendar.getInstance().getTime();
if (currentDate.before(notBefore)) {
return NOT_YET;
} else if(currentDate.after(notBefore) && currentDate.before(notAfter)) {
if (expirationWaterMark > 0) {
//if current_date+watermark>expiration_date
final Date interimBoundryDate = new Date(currentDate.getTime() + expirationWaterMark*60L*1000L);
if(interimBoundryDate.after(notAfter)) {
return ABOUT_TO_EXPIRE;
} else {
return VALID;
}
} else {
//watermark should be n+, but just in case someone abuse it lets have some fallback
final long WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000;
final long DAY_IN_MS = 4 * 60 * 60 * 1000;
long diff = (notAfter.getTime() - notBefore.getTime());
if (diff < WEEK_IN_MS) {
// cert is very short lived, lets settle for 1 day or just mark is as about to expire
if (diff < DAY_IN_MS) {
return ABOUT_TO_EXPIRE;
} else {
diff = DAY_IN_MS;
}
} else {
diff = WEEK_IN_MS;
}
final Date interimBoundryDate = new Date(notAfter.getTime() - diff);
if (currentDate.after(interimBoundryDate)) {
return ABOUT_TO_EXPIRE;
} else {
return VALID;
}
}
} else /*if(currentDate.after(notAfter))*/ {
return EXPIRED;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ interface ElytronDescriptionConstants {
String EVIDENCE_DECODER = "evidence-decoder";
String EVIDENCE_DECODERS = "evidence-decoders";
String EXPIRATION = "expiration";
String EXPIRATION_CHECK_DELAY = "expiration-check-delay";
String EXPIRATION_WATERMARK = "expiration-watermark";
String EXPORT_CERTIFICATE = "export-certificate";
String EXPORT_SECRET_KEY = "export-secret-key";
String EXPRESSION = "expression";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ public class ElytronExtension implements Extension {
/**
* The current name space used for the {@code subsystem} element
*/
static final String NAMESPACE_18_0 = "urn:wildfly:elytron:18.0";
static final String NAMESPACE_19_0 = "urn:wildfly:elytron:19.0";

static final String CURRENT_NAMESPACE = NAMESPACE_18_0;
static final String CURRENT_NAMESPACE = NAMESPACE_19_0;

/**
* The name of our subsystem within the model.
Expand Down Expand Up @@ -76,8 +76,9 @@ public class ElytronExtension implements Extension {
static final ModelVersion ELYTRON_17_0_0 = ModelVersion.create(17);
static final ModelVersion ELYTRON_18_0_0 = ModelVersion.create(18);
static final ModelVersion ELYTRON_19_0_0 = ModelVersion.create(19);
static final ModelVersion ELYTRON_20_0_0 = ModelVersion.create(20, 0);

private static final ModelVersion ELYTRON_CURRENT = ELYTRON_19_0_0;
private static final ModelVersion ELYTRON_CURRENT = ELYTRON_20_0_0;

static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,23 @@ public enum ElytronSubsystemSchema implements PersistentSubsystemSchema<ElytronS
VERSION_17_0(17),
VERSION_18_0(18),
VERSION_18_0_COMMUNITY(18, Stability.COMMUNITY),
VERSION_19_0_COMMUNITY(19, Stability.COMMUNITY),
VERSION_19_0(19),
;
static final Map<Stability, ElytronSubsystemSchema> CURRENT = Feature.map(EnumSet.of(VERSION_18_0, VERSION_18_0_COMMUNITY));
static final Map<Stability, ElytronSubsystemSchema> CURRENT = Feature.map(EnumSet.of(VERSION_19_0, VERSION_19_0_COMMUNITY));

private final VersionedNamespace<IntVersion, ElytronSubsystemSchema> namespace;

ElytronSubsystemSchema(int major) {
ElytronSubsystemSchema(final int major) {
this.namespace = SubsystemSchema.createSubsystemURN(ElytronExtension.SUBSYSTEM_NAME, new IntVersion(major));
}

ElytronSubsystemSchema(int major, int minor) {
this.namespace = SubsystemSchema.createSubsystemURN(ElytronExtension.SUBSYSTEM_NAME, new IntVersion(major, minor));
ElytronSubsystemSchema(final int major, final Stability stability) {
this.namespace = SubsystemSchema.createSubsystemURN(ElytronExtension.SUBSYSTEM_NAME, stability, new IntVersion(major));
}

ElytronSubsystemSchema(int major, Stability stability) {
this.namespace = SubsystemSchema.createSubsystemURN(ElytronExtension.SUBSYSTEM_NAME, stability, new IntVersion(major));
ElytronSubsystemSchema(final int major, final int minor) {
this.namespace = SubsystemSchema.createSubsystemURN(ElytronExtension.SUBSYSTEM_NAME, new IntVersion(major, minor));
}

@Override
Expand Down Expand Up @@ -192,7 +194,13 @@ private void addCredentialStoreParser(PersistentResourceXMLDescription.Persisten

private void addTlsParser(PersistentResourceXMLDescription.PersistentResourceXMLBuilder builder) {
TlsParser tlsParser = new TlsParser();
if (this.since(ElytronSubsystemSchema.VERSION_18_0_COMMUNITY) && this.enables(getDynamicClientSSLContextDefinition())) {
if (this.since(ElytronSubsystemSchema.VERSION_19_0_COMMUNITY)) {
if(this.enables(getDynamicClientSSLContextDefinition())) {
builder.addChild(tlsParser.tlsParserCommunity_19_0_DynamicClientSSL);
} else {
builder.addChild(tlsParser.tlsParserCommunity_19_0);
}
} else if (this.since(ElytronSubsystemSchema.VERSION_18_0_COMMUNITY) && this.enables(getDynamicClientSSLContextDefinition())) {
builder.addChild(tlsParser.tlsParserCommunity_18_0);
} else if (this.since(ElytronSubsystemSchema.VERSION_14_0)) {
builder.addChild(tlsParser.tlsParser_14_0);
Expand Down
Loading
Loading