org.wildfly.security.ssl.CipherSuitePredicate Maven / Gradle / Ivy
The newest version!
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.security.ssl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
/**
* An opaque predicate which can be used to match SSL/TLS cipher suites.
*
* @author David M. Lloyd
*/
public abstract class CipherSuitePredicate {
// constant predicates
private static final CipherSuitePredicate DEFAULTS_PREDICATE = matchAny(
matchEncryption(Encryption.RC2, Encryption.RC4, Encryption.NULL),
matchAuthentication(Authentication.NULL)
);
private static final CipherSuitePredicate ANON_DH_PREDICATE = matchAll(
matchKeyExchange(KeyAgreement.DHd, KeyAgreement.DHr, KeyAgreement.DHE),
matchAuthentication(Authentication.NULL)
);
private static final CipherSuitePredicate OPENSSL_COMPLEMENT_OF_ALL = matchEncryption(Encryption.NULL);
private static final CipherSuitePredicate OPENSSL_DEFAULT_DELETES = matchAny(
matchAuthentication(Authentication.NULL),
matchEncryption(Encryption.NULL),
matchExport(),
matchLevel(SecurityLevel.LOW),
matchProtocol(Protocol.SSLv2)
);
private static final CipherSuitePredicate OPENSSL_COMPLEMENT_OF_DEFAULT = matchAll(
matchAuthentication(Authentication.NULL),
matchNot(matchEncryption(Encryption.NULL))
);
private static final CipherSuitePredicate OPENSSL_ALL = matchNot(OPENSSL_COMPLEMENT_OF_ALL);
CipherSuitePredicate() {
}
static CipherSuitePredicate optimize(CipherSuitePredicate predicate) {
return predicate.isAlwaysFalse() ? matchFalse() : predicate.isAlwaysTrue() ? matchTrue() : predicate;
}
// general logical
/**
* Match all possible cipher suites.
*
* @return the {@code true} predicate
*/
public static CipherSuitePredicate matchTrue() {
return BooleanCipherSuitePredicate.TRUE;
}
/**
* Match no possible cipher suites.
*
* @return the {@code false} predicate
*/
public static CipherSuitePredicate matchFalse() {
return BooleanCipherSuitePredicate.FALSE;
}
/**
* Match all of the given predicates.
*
* @param predicates the predicates
* @return a predicate that is {@code true} when all nested predicates are {@code true}
*/
public static CipherSuitePredicate matchAll(CipherSuitePredicate... predicates) {
return optimize(new AndCipherSuitePredicate(predicates));
}
/**
* Match any of the given predicates.
*
* @param predicates the predicates
* @return a predicate that is {@code true} when any nested predicate is {@code true}
*/
public static CipherSuitePredicate matchAny(CipherSuitePredicate... predicates) {
return optimize(new OrCipherSuitePredicate(predicates));
}
/**
* Invert the given predicate.
*
* @param predicate the predicate
* @return a predicate which is {@code true} when the nested predicate is {@code false}, and vice-versa
*/
public static CipherSuitePredicate matchNot(CipherSuitePredicate predicate) {
return optimize(new NotCipherSuitePredicate(predicate));
}
static T[] withoutNulls(T[] orig) {
if (orig == null) return null;
for (T item : orig) {
if (item == null) {
ArrayList list = null;
for (T item2 : orig) {
if (item2 != null) {
if (list == null) {
list = new ArrayList(orig.length - 1);
}
list.add(item2);
}
}
return list == null ? null : list.toArray(Arrays.copyOf(orig, list.size()));
}
}
// no nulls
return orig;
}
// specific criteria
/**
* Return a predicate which matches the given encryption scheme.
*
* @param encryption the encryption scheme
* @return the predicate
*/
public static CipherSuitePredicate matchEncryption(Encryption encryption) {
return encryption == null ? matchFalse() : new EncryptionCipherSuitePredicate(EnumSet.of(encryption));
}
/**
* Return a predicate which matches any of the given encryption schemes.
*
* @param encryptions the encryption schemes
* @return the predicate
*/
public static CipherSuitePredicate matchEncryption(Encryption... encryptions) {
encryptions = withoutNulls(encryptions);
return encryptions == null || encryptions.length == 0 ? matchFalse() : encryptions.length == Encryption.fullSize ? matchTrue() : new EncryptionCipherSuitePredicate(EnumSet.of(encryptions[0], encryptions));
}
/**
* Return a predicate which matches any of the given encryption schemes.
*
* @param encryptions the encryption schemes
* @return the predicate
*/
public static CipherSuitePredicate matchEncryption(EnumSet encryptions) {
return encryptions == null || encryptions.isEmpty() ? matchFalse() : Encryption.isFull(encryptions) ? matchTrue() : new EncryptionCipherSuitePredicate(encryptions);
}
/**
* Return a predicate which matches the given authentication scheme.
*
* @param authentication the authentication scheme
* @return the predicate
*/
public static CipherSuitePredicate matchAuthentication(Authentication authentication) {
return authentication == null ? matchFalse() : new AuthenticationCipherSuitePredicate(true, EnumSet.of(authentication));
}
/**
* Return a predicate which matches any of the given authentication schemes.
*
* @param authentications the authentication schemes
* @return the predicate
*/
public static CipherSuitePredicate matchAuthentication(Authentication... authentications) {
authentications = withoutNulls(authentications);
return authentications == null || authentications.length == 0 ? matchFalse() : authentications.length == Authentication.fullSize ? matchTrue() : new AuthenticationCipherSuitePredicate(true, EnumSet.of(authentications[0], authentications));
}
/**
* Return a predicate which matches any of the given authentication schemes.
*
* @param authentications the authentication schemes
* @return the predicate
*/
public static CipherSuitePredicate matchAuthentication(EnumSet authentications) {
return authentications == null || authentications.isEmpty() ? matchFalse() : Authentication.isFull(authentications) ? matchTrue() : optimize(new AuthenticationCipherSuitePredicate(true, authentications));
}
/**
* Return a predicate which matches the given key exchange scheme.
*
* @param keyAgreement the key exchange scheme
* @return the predicate
*/
public static CipherSuitePredicate matchKeyAgreement(KeyAgreement keyAgreement) {
return keyAgreement == null ? matchFalse() : new KeyAgreementCipherSuitePredicate(EnumSet.of(keyAgreement));
}
/**
* Return a predicate which matches any of the given key exchange schemes.
*
* @param keyAgreements the key exchange schemes
* @return the predicate
*/
public static CipherSuitePredicate matchKeyExchange(KeyAgreement... keyAgreements) {
keyAgreements = withoutNulls(keyAgreements);
return keyAgreements == null || keyAgreements.length == 0 ? matchFalse() : keyAgreements.length == KeyAgreement.fullSize ? matchTrue() : new KeyAgreementCipherSuitePredicate(EnumSet.of(keyAgreements[0], keyAgreements));
}
/**
* Return a predicate which matches any of the given key exchange schemes.
*
* @param keyAgreements the key exchange schemes
* @return the predicate
*/
public static CipherSuitePredicate matchKeyExchange(EnumSet keyAgreements) {
return keyAgreements == null || keyAgreements.isEmpty() ? matchFalse() : KeyAgreement.isFull(keyAgreements) ? matchTrue() : new KeyAgreementCipherSuitePredicate(keyAgreements);
}
/**
* Return a predicate which matches the given digest scheme.
*
* @param digest the digest scheme
* @return the predicate
*/
public static CipherSuitePredicate matchDigest(Digest digest) {
return digest == null ? matchFalse() : new DigestCipherSuitePredicate(EnumSet.of(digest));
}
/**
* Return a predicate which matches any of the given digest schemes.
*
* @param digests the digest schemes
* @return the predicate
*/
public static CipherSuitePredicate matchDigest(Digest... digests) {
digests = withoutNulls(digests);
return digests == null || digests.length == 0 ? matchFalse() : digests.length == Digest.fullSize ? matchTrue() : new DigestCipherSuitePredicate(EnumSet.of(digests[0], digests));
}
/**
* Return a predicate which matches any of the given digest schemes.
*
* @param digests the digest schemes
* @return the predicate
*/
public static CipherSuitePredicate matchDigest(EnumSet digests) {
return digests == null || digests.isEmpty() ? matchFalse() : Digest.isFull(digests) ? matchTrue() : new DigestCipherSuitePredicate(digests);
}
/**
* Return a predicate which matches the given protocol.
*
* @param protocol the protocol
* @return the predicate
*/
public static CipherSuitePredicate matchProtocol(Protocol protocol) {
return protocol == null ? matchFalse() : new ProtocolCipherSuitePredicate(EnumSet.of(protocol));
}
/**
* Return a predicate which matches any of the given protocols.
*
* @param protocols the protocols
* @return the predicate
*/
public static CipherSuitePredicate matchProtocol(Protocol... protocols) {
protocols = withoutNulls(protocols);
return protocols == null || protocols.length == 0 ? matchFalse() : protocols.length == Protocol.fullSize ? matchTrue() : new ProtocolCipherSuitePredicate(EnumSet.of(protocols[0], protocols));
}
/**
* Return a predicate which matches any of the given protocols.
*
* @param protocols the protocols
* @return the predicate
*/
public static CipherSuitePredicate matchProtocol(EnumSet protocols) {
return protocols == null || protocols.isEmpty() ? matchFalse() : Protocol.isFull(protocols) ? matchTrue() : new ProtocolCipherSuitePredicate(protocols);
}
/**
* Return a predicate which matches the given security level.
*
* @param level the security level
* @return the predicate
*/
public static CipherSuitePredicate matchLevel(SecurityLevel level) {
return level == null ? matchFalse() : new LevelCipherSuitePredicate(EnumSet.of(level));
}
/**
* Return a predicate which matches any of the given security levels.
*
* @param levels the security levels
* @return the predicate
*/
public static CipherSuitePredicate matchLevel(SecurityLevel... levels) {
levels = withoutNulls(levels);
return levels == null || levels.length == 0 ? matchFalse() : levels.length == SecurityLevel.fullSize ? matchTrue() : new LevelCipherSuitePredicate(EnumSet.of(levels[0], levels));
}
/**
* Return a predicate which matches any of the given security levels.
*
* @param levels the security levels
* @return the predicate
*/
public static CipherSuitePredicate matchLevel(EnumSet levels) {
return levels == null || levels.isEmpty() ? matchFalse() : SecurityLevel.isFull(levels) ? matchTrue() : new LevelCipherSuitePredicate(levels);
}
/**
* Return a predicate which matches all security levels less than the given level.
*
* @param level the security level to compare against
* @return the predicate
*/
public static CipherSuitePredicate matchLevelLessThan(final SecurityLevel level) {
return level == null || level == SecurityLevel.NONE ? matchFalse() : new CipherSuitePredicate() {
void toString(final StringBuilder b) {
b.append("security level is less than ").append(level);
}
boolean test(final MechanismDatabase.Entry entry) {
return entry.getLevel().compareTo(level) < 0;
}
};
}
/**
* Return a predicate which matches all FIPS cipher suites.
*
* @return the predicate
*/
public static CipherSuitePredicate matchFips() {
return FipsCipherSuitePredicate.TRUE;
}
/**
* Return a predicate which matches all non-FIPS cipher suites.
*
* @return the predicate
*/
public static CipherSuitePredicate matchNonFips() {
return FipsCipherSuitePredicate.FALSE;
}
/**
* Return a predicate which matches all exportable cipher suites.
*
* @return the predicate
*/
public static CipherSuitePredicate matchExport() {
return ExportCipherSuitePredicate.TRUE;
}
/**
* Return a predicate which matches all non-exportable cipher suites.
*
* @return the predicate
*/
public static CipherSuitePredicate matchNonExport() {
return ExportCipherSuitePredicate.FALSE;
}
/**
* Return a predicate which matches a cipher suite with the given name. The cipher suite name must be a
* standard or OpenSSL-style mechanism name identifying a single mechanism.
*
* @return the predicate
*/
public static CipherSuitePredicate matchName(final String name) {
return name == null ? matchFalse() : new CipherSuitePredicate() {
void toString(final StringBuilder b) {
b.append("cipher name is \"").append(name).append("\"");
}
boolean test(final MechanismDatabase.Entry entry) {
return entry.getOpenSslNames().contains(name) || entry.getAliases().contains(name) || entry.getName().equals(name);
}
};
}
/* -- Our defaults -- */
/**
* Return a predicate which matches all cipher suites that would be fully deleted in the default selector
* configuration.
*
* @return the predicate
*/
public static CipherSuitePredicate matchDefaultDeletes() {
return DEFAULTS_PREDICATE;
}
/* -- OpenSSL specials -- */
/**
* Match all anonymous ciphers which use Diffie-Hellman key exchange.
*
* @return the predicate
*/
public static CipherSuitePredicate matchAnonDH() {
return ANON_DH_PREDICATE;
}
/**
* Match all cipher suites except for anonymous and encryptionless suites, which must be explicitly enabled.
*
* @return the predicate
*/
public static CipherSuitePredicate matchOpenSslAll() {
return OPENSSL_ALL;
}
/**
* Match all cipher suites included by {@link #matchOpenSslAll()} but are disabled by default (generally,
* anonymous Diffie-Hellman suites including elliptic curve suites).
*
* @return the predicate
*/
public static CipherSuitePredicate matchOpenSslComplementOfAll() {
return OPENSSL_COMPLEMENT_OF_ALL;
}
/**
* Match all of the cipher suites which are automatically deleted by OpenSSL when using the special {@code DEFAULT}
* rule.
*
* @return the predicate
*/
public static CipherSuitePredicate matchOpenSslDefaultDeletes() {
return OPENSSL_DEFAULT_DELETES;
}
/**
* Match all of the cipher suites which are added by OpenSSL when using the special {@code COMPLEMENTOFDEFAULT}
* rule.
*
* @return the predicate
*/
public static CipherSuitePredicate matchOpenSslComplementOfDefault() {
return OPENSSL_COMPLEMENT_OF_DEFAULT;
}
abstract void toString(StringBuilder b);
/**
* Get the string representation of this predicate.
*
* @return the string representation of this predicate
*/
public final String toString() {
StringBuilder b = new StringBuilder();
toString(b);
return b.toString();
}
abstract boolean test(MechanismDatabase.Entry entry);
boolean isAlwaysTrue() {
return false;
}
boolean isAlwaysFalse() {
return false;
}
}