api: Add mTLS and Trust/KeyManager Credentials API

This commit is contained in:
Eric Anderson 2021-02-04 16:49:16 -08:00 committed by Eric Anderson
parent 132a40a1cf
commit d937ec5baf
2 changed files with 448 additions and 16 deletions

View File

@ -16,9 +16,19 @@
package io.grpc; package io.grpc;
import com.google.common.io.ByteStreams;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
/** /**
* TLS credentials, providing server authentication and encryption. Consumers of this credential * TLS credentials, providing server authentication and encryption. Consumers of this credential
@ -34,9 +44,82 @@ public final class TlsChannelCredentials extends ChannelCredentials {
} }
private final boolean fakeFeature; private final boolean fakeFeature;
private final byte[] certificateChain;
private final byte[] privateKey;
private final String privateKeyPassword;
private final List<KeyManager> keyManagers;
private final byte[] rootCertificates;
private final List<TrustManager> trustManagers;
TlsChannelCredentials(Builder builder) { TlsChannelCredentials(Builder builder) {
fakeFeature = builder.fakeFeature; fakeFeature = builder.fakeFeature;
certificateChain = builder.certificateChain;
privateKey = builder.privateKey;
privateKeyPassword = builder.privateKeyPassword;
keyManagers = builder.keyManagers;
rootCertificates = builder.rootCertificates;
trustManagers = builder.trustManagers;
}
/**
* The certificate chain for the client's identity, as a new byte array. Generally should be
* PEM-encoded. If {@code null}, some feature is providing key manager information via a different
* method or no client identity is available.
*/
public byte[] getCertificateChain() {
if (certificateChain == null) {
return null;
}
return Arrays.copyOf(certificateChain, certificateChain.length);
}
/**
* The private key for the client's identity, as a new byte array. Generally should be in PKCS#8
* format. If encrypted, {@link #getPrivateKeyPassword} is the decryption key. If unencrypted, the
* password will be {@code null}. If {@code null}, some feature is providing key manager
* information via a different method or no client identity is available.
*/
public byte[] getPrivateKey() {
if (privateKey == null) {
return null;
}
return Arrays.copyOf(privateKey, privateKey.length);
}
/** Returns the password to decrypt the private key, or {@code null} if unencrypted. */
public String getPrivateKeyPassword() {
return privateKeyPassword;
}
/**
* Returns the key manager list which provides the client's identity. Entries are scanned checking
* for specific types, like {@link javax.net.ssl.X509KeyManager}. Only a single entry for a type
* is used. Entries earlier in the list are higher priority. If {@code null}, key manager
* information is provided via a different method or no client identity is available.
*/
public List<KeyManager> getKeyManagers() {
return keyManagers;
}
/**
* Root trust certificates for verifying the server's identity that override the system's
* defaults. Generally PEM-encoded with multiple certificates concatenated.
*/
public byte[] getRootCertificates() {
if (rootCertificates == null) {
return null;
}
return Arrays.copyOf(rootCertificates, rootCertificates.length);
}
/**
* Returns the trust manager list which verifies the server's identity. Entries are scanned
* checking for specific types, like {@link javax.net.ssl.X509TrustManager}. Only a single entry
* for a type is used. Entries earlier in the list are higher priority. If {@code null}, trust
* manager information is provided via the system's default or a different method.
*/
public List<TrustManager> getTrustManagers() {
return trustManagers;
} }
/** /**
@ -71,6 +154,12 @@ public final class TlsChannelCredentials extends ChannelCredentials {
if (fakeFeature) { if (fakeFeature) {
requiredFeature(understoodFeatures, incomprehensible, Feature.FAKE); requiredFeature(understoodFeatures, incomprehensible, Feature.FAKE);
} }
if (rootCertificates != null || privateKey != null || keyManagers != null) {
requiredFeature(understoodFeatures, incomprehensible, Feature.MTLS);
}
if (keyManagers != null || trustManagers != null) {
requiredFeature(understoodFeatures, incomprehensible, Feature.CUSTOM_MANAGERS);
}
return Collections.unmodifiableSet(incomprehensible); return Collections.unmodifiableSet(incomprehensible);
} }
@ -95,6 +184,34 @@ public final class TlsChannelCredentials extends ChannelCredentials {
* a call to {@link #incomprehensible incomprehensible()} is implemented properly. * a call to {@link #incomprehensible incomprehensible()} is implemented properly.
*/ */
FAKE, FAKE,
/**
* Client identity may be provided and server verification can be tuned. This feature requires
* observing {@link #getCertificateChain}, {@link #getPrivateKey}, and {@link
* #getPrivateKeyPassword} as well as {@link #getRootCertificates()}. The certificate chain and
* private key are used to configure a key manager to provide the client's identity. If no
* certificate chain and private key are provided the client will have no identity. The root
* certificates are used to configure a trust manager for verifying the server's identity. If no
* root certificates are provided the trust manager will default to the system's root
* certificates.
*/
MTLS,
/**
* Key managers and trust managers may be specified as {@link KeyManager} and {@link
* TrustManager} objects. This feature requires observing {@link #getKeyManagers()} and {@link
* #getTrustManagers()}. Generally {@link #MTLS} should also be supported, as that is the more
* common method of configuration. When a manager is non-{@code null}, then it is wholly
* responsible for key or trust material and usage; there is no need to check other manager
* sources like {@link #getCertificateChain()} or {@link #getPrivateKey()} (if {@code
* KeyManager} is available), or {@link #getRootCertificates()} (if {@code TrustManager} is
* available).
*
* <p>If other manager sources are available (e.g., {@code getPrivateKey() != null}), then they
* may be alternative representations of the same configuration and the consumer is free to use
* those alternative representations if it prefers. But before doing so it <em>must</em> first
* check that it understands that alternative representation by using {@link #incomprehensible}
* <em>without</em> the {@code CUSTOM_MANAGERS} feature.
*/
CUSTOM_MANAGERS,
; ;
} }
@ -107,6 +224,12 @@ public final class TlsChannelCredentials extends ChannelCredentials {
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/7479") @ExperimentalApi("https://github.com/grpc/grpc-java/issues/7479")
public static final class Builder { public static final class Builder {
private boolean fakeFeature; private boolean fakeFeature;
private byte[] certificateChain;
private byte[] privateKey;
private String privateKeyPassword;
private List<KeyManager> keyManagers;
private byte[] rootCertificates;
private List<TrustManager> trustManagers;
private Builder() {} private Builder() {}
@ -119,6 +242,126 @@ public final class TlsChannelCredentials extends ChannelCredentials {
return this; return this;
} }
/**
* Use the provided certificate chain and private key as the client's identity. Generally they
* should be PEM-encoded and the key is an unencrypted PKCS#8 key (file headers have "BEGIN
* CERTIFICATE" and "BEGIN PRIVATE KEY").
*/
public Builder keyManager(File certChain, File privateKey) throws IOException {
return keyManager(certChain, privateKey, null);
}
/**
* Use the provided certificate chain and possibly-encrypted private key as the client's
* identity. Generally they should be PEM-encoded and the key is a PKCS#8 key. If the private
* key is unencrypted, then password must be {@code null}.
*/
public Builder keyManager(File certChain, File privateKey, String privateKeyPassword)
throws IOException {
InputStream certChainIs = new FileInputStream(certChain);
try {
InputStream privateKeyIs = new FileInputStream(privateKey);
try {
return keyManager(certChainIs, privateKeyIs, privateKeyPassword);
} finally {
privateKeyIs.close();
}
} finally {
certChainIs.close();
}
}
/**
* Use the provided certificate chain and private key as the client's identity. Generally they
* should be PEM-encoded and the key is an unencrypted PKCS#8 key (file headers have "BEGIN
* CERTIFICATE" and "BEGIN PRIVATE KEY").
*/
public Builder keyManager(InputStream certChain, InputStream privateKey) throws IOException {
return keyManager(certChain, privateKey, null);
}
/**
* Use the provided certificate chain and possibly-encrypted private key as the client's
* identity. Generally they should be PEM-encoded and the key is a PKCS#8 key. If the private
* key is unencrypted, then password must be {@code null}.
*/
public Builder keyManager(
InputStream certChain, InputStream privateKey, String privateKeyPassword)
throws IOException {
byte[] certChainBytes = ByteStreams.toByteArray(certChain);
byte[] privateKeyBytes = ByteStreams.toByteArray(privateKey);
clearKeyManagers();
this.certificateChain = certChainBytes;
this.privateKey = privateKeyBytes;
this.privateKeyPassword = privateKeyPassword;
return this;
}
/**
* Have the provided key manager select the client's identity. Although multiple are allowed,
* only the first instance implementing a particular interface is used. So generally there will
* just be a single entry and it implements {@link javax.net.ssl.X509KeyManager}.
*/
public Builder keyManager(KeyManager... keyManagers) {
List<KeyManager> keyManagerList = Collections.unmodifiableList(new ArrayList<>(
Arrays.asList(keyManagers)));
clearKeyManagers();
this.keyManagers = keyManagerList;
return this;
}
private void clearKeyManagers() {
this.certificateChain = null;
this.privateKey = null;
this.privateKeyPassword = null;
this.keyManagers = null;
}
/**
* Use the provided root certificates to verify the server's identity instead of the system's
* default. Generally they should be PEM-encoded with all the certificates concatenated together
* (file header has "BEGIN CERTIFICATE", and would occur once per certificate).
*/
public Builder trustManager(File rootCerts) throws IOException {
InputStream rootCertsIs = new FileInputStream(rootCerts);
try {
return trustManager(rootCertsIs);
} finally {
rootCertsIs.close();
}
}
/**
* Use the provided root certificates to verify the server's identity instead of the system's
* default. Generally they should be PEM-encoded with all the certificates concatenated together
* (file header has "BEGIN CERTIFICATE", and would occur once per certificate).
*/
public Builder trustManager(InputStream rootCerts) throws IOException {
byte[] rootCertsBytes = ByteStreams.toByteArray(rootCerts);
clearTrustManagers();
this.rootCertificates = rootCertsBytes;
return this;
}
/**
* Have the provided trust manager verify the server's identity instead of the system's default.
* Although multiple are allowed, only the first instance implementing a particular interface is
* used. So generally there will just be a single entry and it implements {@link
* javax.net.ssl.X509TrustManager}.
*/
public Builder trustManager(TrustManager... trustManagers) {
List<TrustManager> trustManagerList = Collections.unmodifiableList(new ArrayList<>(
Arrays.asList(trustManagers)));
clearTrustManagers();
this.trustManagers = trustManagerList;
return this;
}
private void clearTrustManagers() {
this.rootCertificates = null;
this.trustManagers = null;
}
/** Construct the credentials. */ /** Construct the credentials. */
public ChannelCredentials build() { public ChannelCredentials build() {
return new TlsChannelCredentials(this); return new TlsChannelCredentials(this);

View File

@ -16,15 +16,20 @@
package io.grpc; package io.grpc;
import com.google.common.base.Preconditions;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.TrustManager;
/** /**
* TLS credentials, providing server identity and encryption. Consumers of this credential must * TLS credentials, providing server identity and encryption. Consumers of this credential must
@ -59,27 +64,44 @@ public final class TlsServerCredentials extends ServerCredentials {
private final byte[] certificateChain; private final byte[] certificateChain;
private final byte[] privateKey; private final byte[] privateKey;
private final String privateKeyPassword; private final String privateKeyPassword;
private final List<KeyManager> keyManagers;
private final ClientAuth clientAuth;
private final byte[] rootCertificates;
private final List<TrustManager> trustManagers;
TlsServerCredentials(Builder builder) { TlsServerCredentials(Builder builder) {
fakeFeature = builder.fakeFeature; fakeFeature = builder.fakeFeature;
certificateChain = builder.certificateChain; certificateChain = builder.certificateChain;
privateKey = builder.privateKey; privateKey = builder.privateKey;
privateKeyPassword = builder.privateKeyPassword; privateKeyPassword = builder.privateKeyPassword;
keyManagers = builder.keyManagers;
clientAuth = builder.clientAuth;
rootCertificates = builder.rootCertificates;
trustManagers = builder.trustManagers;
} }
/** /**
* The certificate chain, as a new byte array. Generally should be PEM-encoded. * The certificate chain for the server's identity, as a new byte array. Generally should be
* PEM-encoded. If {@code null}, some feature is providing key manager information via a different
* method.
*/ */
public byte[] getCertificateChain() { public byte[] getCertificateChain() {
if (certificateChain == null) {
return null;
}
return Arrays.copyOf(certificateChain, certificateChain.length); return Arrays.copyOf(certificateChain, certificateChain.length);
} }
/** /**
* The private key, as a new byte array. Generally should be in PKCS#8 format. If encrypted, * The private key for the server's identity, as a new byte array. Generally should be in PKCS#8
* {@link #getPrivateKeyPassword} is the decryption key. If unencrypted, the password will be * format. If encrypted, {@link #getPrivateKeyPassword} is the decryption key. If unencrypted, the
* {@code null}. * password will be {@code null}. If {@code null}, some feature is providing key manager
* information via a different method.
*/ */
public byte[] getPrivateKey() { public byte[] getPrivateKey() {
if (privateKey == null) {
return null;
}
return Arrays.copyOf(privateKey, privateKey.length); return Arrays.copyOf(privateKey, privateKey.length);
} }
@ -88,6 +110,42 @@ public final class TlsServerCredentials extends ServerCredentials {
return privateKeyPassword; return privateKeyPassword;
} }
/**
* Returns the key manager list which provides the server's identity. Entries are scanned checking
* for specific types, like {@link javax.net.ssl.X509KeyManager}. Only a single entry for a type
* is used. Entries earlier in the list are higher priority. If {@code null}, key manager
* information is provided via a different method.
*/
public List<KeyManager> getKeyManagers() {
return keyManagers;
}
/** Non-{@code null} setting indicating whether the server should expect a client's identity. */
public ClientAuth getClientAuth() {
return clientAuth;
}
/**
* Root trust certificates for verifying the client's identity that override the system's
* defaults. Generally PEM-encoded with multiple certificates concatenated.
*/
public byte[] getRootCertificates() {
if (rootCertificates == null) {
return null;
}
return Arrays.copyOf(rootCertificates, rootCertificates.length);
}
/**
* Returns the trust manager list which verifies the client's identity. Entries are scanned
* checking for specific types, like {@link javax.net.ssl.X509TrustManager}. Only a single entry
* for a type is used. Entries earlier in the list are higher priority. If {@code null}, trust
* manager information is provided via the system's default or a different method.
*/
public List<TrustManager> getTrustManagers() {
return trustManagers;
}
/** /**
* Returns an empty set if this credential can be adequately understood via * Returns an empty set if this credential can be adequately understood via
* the features listed, otherwise returns a hint of features that are lacking * the features listed, otherwise returns a hint of features that are lacking
@ -120,6 +178,12 @@ public final class TlsServerCredentials extends ServerCredentials {
if (fakeFeature) { if (fakeFeature) {
requiredFeature(understoodFeatures, incomprehensible, Feature.FAKE); requiredFeature(understoodFeatures, incomprehensible, Feature.FAKE);
} }
if (clientAuth != ClientAuth.NONE) {
requiredFeature(understoodFeatures, incomprehensible, Feature.MTLS);
}
if (keyManagers != null || trustManagers != null) {
requiredFeature(understoodFeatures, incomprehensible, Feature.CUSTOM_MANAGERS);
}
return Collections.unmodifiableSet(incomprehensible); return Collections.unmodifiableSet(incomprehensible);
} }
@ -139,10 +203,37 @@ public final class TlsServerCredentials extends ServerCredentials {
* a call to {@link #incomprehensible incomprehensible()} is implemented properly. * a call to {@link #incomprehensible incomprehensible()} is implemented properly.
*/ */
FAKE, FAKE,
/**
* Client certificates may be requested and verified. This feature requires observing {@link
* #getRootCertificates()} and {@link #getClientAuth()}. The root certificates are used to
* configure a trust manager for verifying the client's identity. If no root certificates are
* provided the trust manager will default to the system's root certificates.
*/
MTLS,
/**
* Key managers and trust managers may be specified as {@link KeyManager} and {@link
* TrustManager} objects. This feature by itself only implies {@link #getKeyManagers()} needs to
* be observed. But along with {@link #MTLS}, then {@link #getTrustManagers()} needs to be
* observed as well. When a manager is non-{@code null}, then it is wholly responsible for key
* or trust material and usage; there is no need to check other manager sources like {@link
* #getCertificateChain()} or {@link #getPrivateKey()} (if {@code KeyManager} is available), or
* {@link #getRootCertificates()} (if {@code TrustManager} is available).
*
* <p>If other manager sources are available (e.g., {@code getPrivateKey() != null}), then they
* may be alternative representations of the same configuration and the consumer is free to use
* those alternative representations if it prefers. But before doing so it <em>must</em> first
* check that it understands that alternative representation by using {@link #incomprehensible}
* <em>without</em> the {@code CUSTOM_MANAGERS} feature.
*/
CUSTOM_MANAGERS,
; ;
} }
/** Creates a builder for changing default configuration. */ /**
* Creates a builder for changing default configuration. There is no default key manager, so key
* material must be specified. The default trust manager uses the system's root certificates. By
* default no client authentication will occur.
*/
public static Builder newBuilder() { public static Builder newBuilder() {
return new Builder(); return new Builder();
} }
@ -154,6 +245,10 @@ public final class TlsServerCredentials extends ServerCredentials {
private byte[] certificateChain; private byte[] certificateChain;
private byte[] privateKey; private byte[] privateKey;
private String privateKeyPassword; private String privateKeyPassword;
private List<KeyManager> keyManagers;
private ClientAuth clientAuth = ClientAuth.NONE;
private byte[] rootCertificates;
private List<TrustManager> trustManagers;
private Builder() {} private Builder() {}
@ -167,8 +262,8 @@ public final class TlsServerCredentials extends ServerCredentials {
} }
/** /**
* Creates an instance using provided certificate chain and private key. Generally they should * Use the provided certificate chain and private key as the server's identity. Generally they
* be PEM-encoded and the key is an unencrypted PKCS#8 key (file headers have "BEGIN * should be PEM-encoded and the key is an unencrypted PKCS#8 key (file headers have "BEGIN
* CERTIFICATE" and "BEGIN PRIVATE KEY"). * CERTIFICATE" and "BEGIN PRIVATE KEY").
*/ */
public Builder keyManager(File certChain, File privateKey) throws IOException { public Builder keyManager(File certChain, File privateKey) throws IOException {
@ -176,9 +271,9 @@ public final class TlsServerCredentials extends ServerCredentials {
} }
/** /**
* Creates an instance using provided certificate chain and possibly-encrypted private key. * Use the provided certificate chain and possibly-encrypted private key as the server's
* Generally they should be PEM-encoded and the key is a PKCS#8 key. If the private key is * identity. Generally they should be PEM-encoded and the key is a PKCS#8 key. If the private
* unencrypted, then password must be {@code null}. * key is unencrypted, then password must be {@code null}.
*/ */
public Builder keyManager(File certChain, File privateKey, String privateKeyPassword) public Builder keyManager(File certChain, File privateKey, String privateKeyPassword)
throws IOException { throws IOException {
@ -196,8 +291,8 @@ public final class TlsServerCredentials extends ServerCredentials {
} }
/** /**
* Creates an instance using provided certificate chain and private key. Generally they should * Use the provided certificate chain and private key as the server's identity. Generally they
* be PEM-encoded and the key is an unencrypted PKCS#8 key (file headers have "BEGIN * should be PEM-encoded and the key is an unencrypted PKCS#8 key (file headers have "BEGIN
* CERTIFICATE" and "BEGIN PRIVATE KEY"). * CERTIFICATE" and "BEGIN PRIVATE KEY").
*/ */
public Builder keyManager(InputStream certChain, InputStream privateKey) throws IOException { public Builder keyManager(InputStream certChain, InputStream privateKey) throws IOException {
@ -205,27 +300,121 @@ public final class TlsServerCredentials extends ServerCredentials {
} }
/** /**
* Creates an instance using provided certificate chain and possibly-encrypted private key. * Use the provided certificate chain and possibly-encrypted private key as the server's
* Generally they should be PEM-encoded and the key is a PKCS#8 key. If the private key is * identity. Generally they should be PEM-encoded and the key is a PKCS#8 key. If the private
* unencrypted, then password must be {@code null}. * key is unencrypted, then password must be {@code null}.
*/ */
public Builder keyManager( public Builder keyManager(
InputStream certChain, InputStream privateKey, String privateKeyPassword) InputStream certChain, InputStream privateKey, String privateKeyPassword)
throws IOException { throws IOException {
byte[] certChainBytes = ByteStreams.toByteArray(certChain); byte[] certChainBytes = ByteStreams.toByteArray(certChain);
byte[] privateKeyBytes = ByteStreams.toByteArray(privateKey); byte[] privateKeyBytes = ByteStreams.toByteArray(privateKey);
clearKeyManagers();
this.certificateChain = certChainBytes; this.certificateChain = certChainBytes;
this.privateKey = privateKeyBytes; this.privateKey = privateKeyBytes;
this.privateKeyPassword = privateKeyPassword; this.privateKeyPassword = privateKeyPassword;
return this; return this;
} }
/**
* Have the provided key manager select the server's identity. Although multiple are allowed,
* only the first instance implementing a particular interface is used. So generally there will
* just be a single entry and it implements {@link javax.net.ssl.X509KeyManager}.
*/
public Builder keyManager(KeyManager... keyManagers) {
List<KeyManager> keyManagerList = Collections.unmodifiableList(new ArrayList<>(
Arrays.asList(keyManagers)));
clearKeyManagers();
this.keyManagers = keyManagerList;
return this;
}
private void clearKeyManagers() {
this.certificateChain = null;
this.privateKey = null;
this.privateKeyPassword = null;
this.keyManagers = null;
}
/**
* Indicates whether the server should expect a client's identity. Must not be {@code null}.
* Defaults to {@link ClientAuth#NONE}.
*/
public Builder clientAuth(ClientAuth clientAuth) {
Preconditions.checkNotNull(clientAuth, "clientAuth");
this.clientAuth = clientAuth;
return this;
}
/**
* Use the provided root certificates to verify the client's identity instead of the system's
* default. Generally they should be PEM-encoded with all the certificates concatenated together
* (file header has "BEGIN CERTIFICATE", and would occur once per certificate).
*/
public Builder trustManager(File rootCerts) throws IOException {
InputStream rootCertsIs = new FileInputStream(rootCerts);
try {
return trustManager(rootCertsIs);
} finally {
rootCertsIs.close();
}
}
/**
* Use the provided root certificates to verify the client's identity instead of the system's
* default. Generally they should be PEM-encoded with all the certificates concatenated together
* (file header has "BEGIN CERTIFICATE", and would occur once per certificate).
*/
public Builder trustManager(InputStream rootCerts) throws IOException {
byte[] rootCertsBytes = ByteStreams.toByteArray(rootCerts);
clearTrustManagers();
this.rootCertificates = rootCertsBytes;
return this;
}
/**
* Have the provided trust manager verify the client's identity instead of the system's default.
* Although multiple are allowed, only the first instance implementing a particular interface is
* used. So generally there will just be a single entry and it implements {@link
* javax.net.ssl.X509TrustManager}.
*/
public Builder trustManager(TrustManager... trustManagers) {
List<TrustManager> trustManagerList = Collections.unmodifiableList(new ArrayList<>(
Arrays.asList(trustManagers)));
clearTrustManagers();
this.trustManagers = trustManagerList;
return this;
}
private void clearTrustManagers() {
this.rootCertificates = null;
this.trustManagers = null;
}
/** Construct the credentials. */ /** Construct the credentials. */
public ServerCredentials build() { public ServerCredentials build() {
if (certificateChain == null) { if (certificateChain == null && keyManagers == null) {
throw new IllegalStateException("A key manager is required"); throw new IllegalStateException("A key manager is required");
} }
return new TlsServerCredentials(this); return new TlsServerCredentials(this);
} }
} }
/** The level of authentication the server should expect from the client. */
public enum ClientAuth {
/** Clients will not present any identity. */
NONE,
/**
* Clients are requested to present their identity, but clients without identities are
* permitted.
*/
OPTIONAL,
/**
* Clients are requested to present their identity, and are required to provide a valid
* identity.
*/
REQUIRE;
}
} }