Path: blob/master/test/jdk/javax/net/ssl/TLSCommon/TLSWithEdDSA.java
41152 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* SunJSSE does not support dynamic system properties, no way to re-use25* system properties in samevm/agentvm mode.26* For extra debugging output, add -Djavax.net.debug=ssl:handshake into the27* run directive below.28*/2930/*31* @test32* @bug 816659633* @summary TLS support for the EdDSA signature algorithm34* @library /javax/net/ssl/templates /test/lib35* @run main/othervm TLSWithEdDSA36*/3738import java.io.ByteArrayInputStream;39import java.io.IOException;40import java.io.InputStream;41import java.io.OutputStream;42import java.net.Socket;43import java.net.SocketException;44import java.nio.charset.Charset;45import java.security.GeneralSecurityException;46import java.security.KeyFactory;47import java.security.KeyStore;48import java.security.KeyStoreException;49import java.security.Principal;50import java.security.PrivateKey;51import java.security.PublicKey;52import java.security.cert.Certificate;53import java.security.cert.CertificateException;54import java.security.cert.CertificateFactory;55import java.security.cert.PKIXBuilderParameters;56import java.security.cert.X509CertSelector;57import java.security.cert.X509Certificate;58import java.security.interfaces.ECKey;59import java.security.interfaces.EdECKey;60import java.security.spec.PKCS8EncodedKeySpec;61import java.util.*;62import javax.net.ssl.CertPathTrustManagerParameters;63import javax.net.ssl.KeyManager;64import javax.net.ssl.KeyManagerFactory;65import javax.net.ssl.SSLContext;66import javax.net.ssl.SSLPeerUnverifiedException;67import javax.net.ssl.SSLServerSocket;68import javax.net.ssl.SSLSession;69import javax.net.ssl.SSLSocket;70import javax.net.ssl.TrustManagerFactory;71import javax.net.ssl.X509ExtendedKeyManager;72import javax.net.ssl.X509KeyManager;73import jdk.test.lib.security.SecurityUtils;7475public class TLSWithEdDSA extends SSLSocketTemplate {76private static final String PASSWD = "passphrase";77private static final String DEF_TRUST_ANCHORS = "CA_DSA_1024:CA_DSA_2048:" +78"CA_ECDSA_SECP256R1:CA_ECDSA_SECP384R1:CA_ECDSA_SECP521R1:" +79"CA_ED25519:CA_ED448:CA_RSA_2048";80private static final String DEF_ALL_EE = "EE_ECDSA_SECP256R1:" +81"EE_ECDSA_SECP384R1:EE_ECDSA_SECP521R1:EE_RSA_2048:" +82"EE_EC_RSA_SECP256R1:EE_DSA_2048:EE_DSA_1024:EE_ED25519:EE_ED448";83private static final List<String> TEST_PROTOS = List.of(84"TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1");8586private static CertificateFactory certFac;87private static final Map<ParamType, String> clientParameters =88new HashMap<>();89private static final Map<ParamType, String> serverParameters =90new HashMap<>();9192private final SessionChecker clientChecker;93private final SessionChecker serverChecker;94private final Class<? extends Throwable> clientException;95private final Class<? extends Throwable> serverException;9697interface SessionChecker {98public void check(SSLSocket socket);99}100101/**102* Checks to make sure the end-entity certificate presented by the103* peer uses and Ed25519 key.104*/105final static SessionChecker isPeerEd25519 = new SessionChecker() {106@Override107public void check(SSLSocket sock) {108try {109SSLSession session = sock.getSession();110System.out.println("Peer certificate check for Ed25519:\n" +111sessionDump(session));112Certificate[] serverCertChain = session.getPeerCertificates();113X509Certificate tlsCert = (X509Certificate)serverCertChain[0];114keyCheck(tlsCert.getPublicKey(), "EdDSA", "Ed25519");115} catch (SSLPeerUnverifiedException sslpe) {116throw new RuntimeException(sslpe);117}118}119};120121/**122* Checks to make sure the end-entity certificate presented by the123* peer uses and Ed448 key.124*/125final static SessionChecker isPeerEd448 = new SessionChecker() {126@Override127public void check(SSLSocket sock) {128try {129SSLSession session = sock.getSession();130System.out.println("Peer certificate check for Ed448:\n" +131sessionDump(session));132Certificate[] serverCertChain = session.getPeerCertificates();133X509Certificate tlsCert = (X509Certificate)serverCertChain[0];134keyCheck(tlsCert.getPublicKey(), "EdDSA", "Ed448");135} catch (SSLPeerUnverifiedException sslpe) {136throw new RuntimeException(sslpe);137}138}139};140141/**142* Checks to make sure the end-entity certificate presented by the143* peer uses an EC secp521r1 key.144*/145final static SessionChecker isPeerP521 = new SessionChecker() {146@Override147public void check(SSLSocket sock) {148try {149SSLSession session = sock.getSession();150System.out.println("Peer certificate check for secp521r1:\n" +151sessionDump(session));152Certificate[] serverCertChain = session.getPeerCertificates();153X509Certificate tlsCert = (X509Certificate)serverCertChain[0];154keyCheck(tlsCert.getPublicKey(), "EC", "secp521r1");155} catch (SSLPeerUnverifiedException sslpe) {156throw new RuntimeException(sslpe);157}158}159};160161/**162* Returns a String summary of an SSLSession object163*164* @param sess the SSLSession object to be dumped165*166* @return a String representation of the test-relevant portions of the167* SSLSession object.168*/169private static String sessionDump(SSLSession sess) {170StringBuilder sb = new StringBuilder();171sb.append("----- Session Info -----\n");172sb.append("Protocol: ").append(sess.getProtocol()).append("\n");173sb.append("Cipher Suite: ").append(sess.getCipherSuite());174Certificate[] localCerts = sess.getLocalCertificates();175if (localCerts != null) {176sb.append("\nLocal Certs:");177int i = 0;178for (Certificate cert : localCerts) {179sb.append(String.format("\n [%d]: %s", i++,180((X509Certificate)cert).getSubjectX500Principal()));181}182}183try {184Certificate[] peerCerts = sess.getPeerCertificates();185if (peerCerts != null) {186sb.append("\nPeer Certs:");187int i = 0;188for (Certificate cert : peerCerts) {189sb.append(String.format("\n [%d]: %s", i++,190((X509Certificate)cert).getSubjectX500Principal()));191}192}193} catch (SSLPeerUnverifiedException sslex) {194throw new RuntimeException(sslex);195}196197return sb.toString();198}199200/**201* Checks to make sure the public key conforms to the expected key type202* and (where applicable) curve.203*204* @param pubKey the public key to be checked205* @param expPkType the expected key type (RSA/DSA/EC/EdDSA)206* @param expCurveName if an EC/EdDSA key, the expected curve207*/208private static void keyCheck(PublicKey pubKey, String expPkType,209String expCurveName) {210String curveName = null;211String pubKeyAlg = pubKey.getAlgorithm();212if (!expPkType.equalsIgnoreCase(pubKeyAlg)) {213throw new RuntimeException("Expected " + expPkType + " key, got " +214pubKeyAlg);215}216217// Check the curve type218if (expCurveName != null) {219switch (pubKeyAlg) {220case "EdDSA":221curveName = ((EdECKey)pubKey).getParams().getName().222toLowerCase();223if (!expCurveName.equalsIgnoreCase(curveName)) {224throw new RuntimeException("Expected " + expCurveName +225" curve, " + "got " + curveName);226}227break;228case "EC":229curveName = ((ECKey)pubKey).getParams().toString().230toLowerCase();231if (!curveName.contains(expCurveName.toLowerCase())) {232throw new RuntimeException("Expected " + expCurveName +233" curve, " + "got " + curveName);234}235break;236default:237throw new IllegalArgumentException(238"Unsupported key type: " + pubKeyAlg);239}240}241System.out.format("Found key: %s / %s\n", pubKeyAlg,242curveName != null ? curveName : "");243}244245TLSWithEdDSA(SessionChecker cliChk, Class<? extends Throwable> cliExpExc,246SessionChecker servChk, Class<? extends Throwable> servExpExc) {247super();248clientChecker = cliChk;249clientException = cliExpExc;250serverChecker = servChk;251serverException = servExpExc;252}253254/**255* Creates an SSLContext for use with the client side of this test. This256* uses parameters held in the static client parameters map.257*258* @return an initialized SSLContext for use with the client.259*260* @throws Exception if any downstream errors occur during key store261* creation, key/trust manager factory creation or context262* initialization.263*/264@Override265protected SSLContext createClientSSLContext() throws Exception {266KeyStore clientKeyStore = createKeyStore(267clientParameters.getOrDefault(ParamType.KSENTRIES, ""),268PASSWD.toCharArray());269KeyStore clientTrustStore = createTrustStore(270clientParameters.getOrDefault(ParamType.TSENTRIES,271DEF_TRUST_ANCHORS));272return createCtxCommon(clientKeyStore,273clientParameters.get(ParamType.CERTALIAS), PASSWD.toCharArray(),274clientTrustStore, "jdk.tls.client.SignatureSchemes",275clientParameters.get(ParamType.SIGALGS));276}277278/**279* Creates an SSLContext for use with the server side of this test. This280* uses parameters held in the static server parameters map.281*282* @return an initialized SSLContext for use with the server.283*284* @throws Exception if any downstream errors occur during key store285* creation, key/trust manager factory creation or context286* initialization.287*/288@Override289protected SSLContext createServerSSLContext() throws Exception {290KeyStore serverKeyStore = createKeyStore(291serverParameters.getOrDefault(ParamType.KSENTRIES, ""),292PASSWD.toCharArray());293KeyStore serverTrustStore = createTrustStore(294serverParameters.getOrDefault(ParamType.TSENTRIES,295DEF_TRUST_ANCHORS));296return createCtxCommon(serverKeyStore,297serverParameters.get(ParamType.CERTALIAS), PASSWD.toCharArray(),298serverTrustStore, "jdk.tls.server.SignatureSchemes",299serverParameters.get(ParamType.SIGALGS));300}301302/**303* Create a trust store containing any CA certificates designated as304* trust anchors.305*306* @return the trust store populated with the root CA certificate.307*308* @throws GeneralSecurityException if any certificates cannot be added to309* the key store.310*/311private static KeyStore createTrustStore(String certEnumNames)312throws GeneralSecurityException {313KeyStore.Builder keyStoreBuilder =314KeyStore.Builder.newInstance("PKCS12", null,315new KeyStore.PasswordProtection(PASSWD.toCharArray()));316KeyStore ks = keyStoreBuilder.getKeyStore();317for (String certName : certEnumNames.split(":")) {318try {319SSLSocketTemplate.Cert cert =320SSLSocketTemplate.Cert.valueOf(certName);321ks.setCertificateEntry(certName, pem2Cert(cert.certStr));322} catch (IllegalArgumentException iae) {323System.out.println("Unable to find Cert enum entry for " +324certName + ", skipping");325}326}327return ks;328}329330/**331* Create a key store containing any end-entity private keys/certs332* specified in the parameters.333*334* @param certEnumNames a colon-delimited list of String values that are335* the names of the SSLSocketTemplate.Cert enumeration entries.336* @param pass the desired password for the resulting KeyStore object.337*338* @return a populated, loaded KeyStore ready for use.339*340* @throws GeneralSecurityException if any issues occur while setting341* the private key or certificate entries.342*/343private static KeyStore createKeyStore(String certEnumNames, char[] pass)344throws GeneralSecurityException {345KeyStore.Builder keyStoreBuilder =346KeyStore.Builder.newInstance("PKCS12", null,347new KeyStore.PasswordProtection(pass));348KeyStore ks = keyStoreBuilder.getKeyStore();349if (certEnumNames != null && !certEnumNames.isEmpty()) {350for (String certName : certEnumNames.split(":")) {351try {352SSLSocketTemplate.Cert cert =353SSLSocketTemplate.Cert.valueOf(certName);354ks.setKeyEntry(certName,355pem2PrivKey(cert.privKeyStr, cert.keyAlgo), pass,356new Certificate[] { pem2Cert(cert.certStr) });357} catch (IllegalArgumentException iae) {358System.out.println("Unable to find Cert enum entry for " +359certName + ", skipping");360}361}362}363364return ks;365}366367/**368* Covert a PEM-encoded certificate into a X509Certificate object.369*370* @param certPem the PEM encoding for the certificate.371*372* @return the corresponding X509Certificate object for the provided PEM.373*374* @throws CertificateException if any decoding errors occur.375*/376private static X509Certificate pem2Cert(String certPem)377throws CertificateException {378return (X509Certificate)certFac.generateCertificate(379new ByteArrayInputStream(certPem.getBytes(380Charset.forName("UTF-8"))));381}382383/**384* Covert a PEM-encoded PKCS8 private key into a PrivateKey object.385*386* @param keyPem the PEM encoding for the certificate.387* @param keyAlg the algorithm for the private key contained in the PKCS8388* ` encoding.389*390* @return the corresponding PrivateKey object for the provided PEM.391*392* @throws GeneralSecurityException if any decoding errors occur.393*/394private static PrivateKey pem2PrivKey(String keyPem, String keyAlg)395throws GeneralSecurityException {396PKCS8EncodedKeySpec p8Spec = new PKCS8EncodedKeySpec(397Base64.getMimeDecoder().decode(keyPem));398KeyFactory keyFac = KeyFactory.getInstance(keyAlg);399return keyFac.generatePrivate(p8Spec);400}401402/**403* Create an SSLContext for use with the client or server sides of this404* test.405*406* @param keys the key store object for this SSLContext.407* @param alias optional alias specifier to exclusively use that alias for408* TLS connections.409* @param pass the key store password410* @param trust the trust store object411* @param sigAlgProp the signature algorithm property name to set412* (reserved for future use pending the fix for JDK-8255867)413* @param sigAlgVal the property value to be applied.414*415* @return an initialized SSLContext object.416*417* @throws IOException if any IOExceptions during manager factory creation418* take place419* @throws GeneralSecurityException any other failure during SSLContext420* creation/initialization421*/422private static SSLContext createCtxCommon(KeyStore keys, String alias,423char[] pass, KeyStore trust, String sigAlgProp, String sigAlgVal)424throws IOException, GeneralSecurityException {425SSLContext ctx;426if (sigAlgVal != null && !sigAlgVal.isEmpty()) {427System.setProperty(sigAlgProp, sigAlgVal);428}429430// If an alias is specified use our local AliasKeyManager431KeyManager[] kms = (alias != null && !alias.isEmpty()) ?432new KeyManager[] { new AliasKeyManager(keys, pass, alias) } :433createKeyManagerFactory(keys, pass).getKeyManagers();434435ctx = SSLContext.getInstance("TLS");436ctx.init(kms, createTrustManagerFactory(trust).getTrustManagers(),437null);438return ctx;439}440441/**442* Creates a KeyManagerFactory for use during SSLContext initialization.443*444* @param ks the KeyStore forming the base of the KeyManagerFactory445* @param passwd the password to use for the key store446*447* @return the initialized KeyManagerFactory448*449* @throws IOException any IOExceptions during key manager factory450* initialization.451* @throws GeneralSecurityException if any failures during instantiation452* take place.453*/454private static KeyManagerFactory createKeyManagerFactory(KeyStore ks,455char[] passwd) throws IOException, GeneralSecurityException {456KeyManagerFactory kmf;457kmf = KeyManagerFactory.getInstance("SunX509");458kmf.init(ks, passwd);459460KeyManager[] kmgrs = kmf.getKeyManagers();461X509ExtendedKeyManager xkm = (X509ExtendedKeyManager)kmgrs[0];462return kmf;463}464465/**466* Creates a TrustManagerFactory for use during SSLContext initialization.467*468* @param trustStrore the KeyStore forming the base of the469* TrustManagerFactory470*471* @return the initialized TrustManagerFactory472*473* @throws IOException any IOExceptions during trust manager factory474* initialization.475* @throws GeneralSecurityException if any failures during instantiation476* take place.477*/478private static TrustManagerFactory createTrustManagerFactory(479KeyStore trustStore) throws IOException, GeneralSecurityException {480TrustManagerFactory tmf;481PKIXBuilderParameters pkixParams =482new PKIXBuilderParameters(trustStore, new X509CertSelector());483pkixParams.setRevocationEnabled(false);484tmf = TrustManagerFactory.getInstance("PKIX");485tmf.init(new CertPathTrustManagerParameters(pkixParams));486return tmf;487}488489/*490* Configure the client side socket.491*/492@Override493protected void configureClientSocket(SSLSocket socket) {494String pVal;495if ((pVal = clientParameters.get(ParamType.PROTOS)) != null) {496socket.setEnabledProtocols(pVal.split(":"));497}498499if ((pVal = clientParameters.get(ParamType.CIPHERS)) != null) {500socket.setEnabledCipherSuites(pVal.split(":"));501}502}503504/*505* Configure the server side socket.506*/507@Override508protected void configureServerSocket(SSLServerSocket socket) {509String pVal;510try {511socket.setReuseAddress(true);512if ((pVal = serverParameters.get(ParamType.PROTOS)) != null) {513socket.setEnabledProtocols(pVal.split(":"));514}515516if ((pVal = serverParameters.get(ParamType.CIPHERS)) != null) {517socket.setEnabledCipherSuites(pVal.split(":"));518}519520pVal = serverParameters.get(ParamType.CLIAUTH);521socket.setWantClientAuth("WANT".equalsIgnoreCase(pVal));522socket.setNeedClientAuth("NEED".equalsIgnoreCase(pVal));523} catch (SocketException se) {524throw new RuntimeException(se);525}526}527528529@Override530protected void runServerApplication(SSLSocket socket) throws Exception {531InputStream sslIS = socket.getInputStream();532OutputStream sslOS = socket.getOutputStream();533534sslIS.read();535sslOS.write(85);536sslOS.flush();537538if (serverChecker != null) {539serverChecker.check(socket);540}541}542543@Override544protected void runClientApplication(SSLSocket socket) throws Exception {545InputStream sslIS = socket.getInputStream();546OutputStream sslOS = socket.getOutputStream();547548sslOS.write(280);549sslOS.flush();550sslIS.read();551552if (clientChecker != null) {553clientChecker.check(socket);554}555}556557public static void main(String[] args) throws Exception {558SecurityUtils.removeFromDisabledTlsAlgs("TLSv1.1", "TLSv1");559certFac = CertificateFactory.getInstance("X.509");560String testFormat;561562System.out.println("===== Test KeyManager alias retrieval =====");563testKeyManager(DEF_ALL_EE, "EdDSA",564new String[] {"ee_ed25519", "ee_ed448"});565566testFormat =567"===== Basic Ed25519 Server-side Authentication: %s =====\n";568serverParameters.put(ParamType.KSENTRIES, "EE_ED25519:EE_RSA_2048");569runtest(testFormat, isPeerEd25519, null, null, null);570571testFormat =572"===== Basic Ed448 Server-side Authentication: %s =====\n";573serverParameters.put(ParamType.KSENTRIES, "EE_ED448:EE_RSA_2048");574runtest(testFormat, isPeerEd448, null, null, null);575576testFormat = "===== EC favored over EdDSA by default: %s =====\n";577serverParameters.put(ParamType.KSENTRIES,578"EE_ED25519:EE_ECDSA_SECP521R1");579runtest(testFormat, isPeerP521, null, null, null);580581testFormat = "===== Override EC favoring by alias: %s =====\n";582serverParameters.put(ParamType.CERTALIAS, "EE_ED25519");583runtest(testFormat, isPeerEd25519, null, null, null);584serverParameters.remove(ParamType.CERTALIAS);585586testFormat = "===== EdDSA Client Authentication: %s =====\n";587serverParameters.put(ParamType.KSENTRIES, "EE_RSA_2048");588serverParameters.put(ParamType.CLIAUTH, "NEED");589clientParameters.put(ParamType.KSENTRIES, "EE_ED25519");590runtest(testFormat, null, null, isPeerEd25519, null);591}592593private static void testKeyManager(String keyStoreSpec, String keyType,594String[] expAliases)595throws GeneralSecurityException, IOException {596char[] passChar = PASSWD.toCharArray();597598// Create the KeyManager factory and resulting KeyManager599KeyManagerFactory kmf = createKeyManagerFactory(600createKeyStore(keyStoreSpec, passChar), passChar);601KeyManager[] kMgrs = kmf.getKeyManagers();602X509KeyManager xkm = (X509KeyManager)kMgrs[0];603604String[] cliEdDSAAlises = xkm.getClientAliases(keyType, null);605System.out.format("Client Aliases (%s): ", keyType);606for (String alias : cliEdDSAAlises) {607System.out.print(alias + " ");608}609System.out.println();610611String[] servEdDSAAliases = xkm.getServerAliases(keyType, null);612System.out.format("Server Aliases (%s): ", keyType);613for (String alias : servEdDSAAliases) {614System.out.print(alias + " ");615}616System.out.println();617618if (!Arrays.equals(cliEdDSAAlises, expAliases)) {619throw new RuntimeException("Client alias mismatch");620} else if (!Arrays.equals(servEdDSAAliases, expAliases)) {621throw new RuntimeException("Server alias mismatch");622}623}624625private static void runtest(String testNameFmt, SessionChecker cliChk,626Class<? extends Throwable> cliExpExc, SessionChecker servChk,627Class<? extends Throwable> servExpExc) {628TEST_PROTOS.forEach(protocol -> {629clientParameters.put(ParamType.PROTOS, protocol);630TLSWithEdDSA testObj = new TLSWithEdDSA(cliChk, cliExpExc, servChk,631servExpExc);632System.out.format(testNameFmt, protocol);633try {634testObj.run();635if (testObj.clientException != null ||636testObj.serverException != null) {637throw new RuntimeException("Expected exception from " +638"either client or server but was missed");639}640} catch (Exception exc) {641if (testObj.clientException == null &&642testObj.serverException == null) {643throw new RuntimeException(644"Expected test failure did not occur");645} else if (testObj.clientException != null &&646!testObj.clientException.isAssignableFrom(exc.getClass())) {647throw new RuntimeException("Unexpected client exception " +648"detected: Expected " +649testObj.clientException.getName() +650", got " + exc.getClass().getName());651652} else if (testObj.serverException != null &&653!testObj.serverException.isAssignableFrom(exc.getClass())) {654throw new RuntimeException("Unexpected client exception " +655"detected: Expected " +656testObj.serverException.getName() +657", got " + exc.getClass().getName());658}659}660System.out.println();661});662}663664/**665* A Custom KeyManager that allows the user to specify a key/certificate666* by alias to be used for any TLS authentication actions.667*/668static class AliasKeyManager implements X509KeyManager {669private final String alias;670private final KeyStore keystore;671private final char[] pass;672673public AliasKeyManager(KeyStore keystore, char[] pass, String alias) {674this.keystore = Objects.requireNonNull(keystore);675this.alias = Objects.requireNonNull(alias);676this.pass = Objects.requireNonNull(pass);677}678679@Override680public PrivateKey getPrivateKey(String alias) {681try {682return (PrivateKey)keystore.getKey(alias, pass);683} catch (GeneralSecurityException exc) {684throw new RuntimeException(exc);685}686}687688@Override689public X509Certificate[] getCertificateChain(String alias) {690try {691Certificate[] certAr = keystore.getCertificateChain(alias);692return (certAr != null) ? Arrays.copyOf(certAr, certAr.length,693X509Certificate[].class) : null;694} catch (KeyStoreException ke) {695throw new RuntimeException(ke);696}697}698699@Override700public String chooseClientAlias(String[] keyType, Principal[] issuers,701Socket socket) {702// Blindly return the one selected alias.703return alias;704}705706@Override707public String chooseServerAlias(String keyType, Principal[] issuers,708Socket socket) {709// Blindly return the one selected alias.710return alias;711}712713@Override714public String[] getClientAliases(String keyType, Principal[] issuers) {715// There can be only one!716return new String[] { alias };717}718719@Override720public String[] getServerAliases(String keyType, Principal[] issuers) {721// There can be only one!722return new String[] { alias };723}724}725726static enum ParamType {727PROTOS,728CIPHERS,729SIGALGS,730CLIAUTH,731KSENTRIES,732TSENTRIES,733CERTALIAS734}735}736737