| /*========================================================================= |
| * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved. |
| * This product is protected by U.S. and international copyright |
| * and intellectual property laws. Pivotal products are covered by |
| * more patents listed at http://www.pivotal.io/patents. |
| *========================================================================= |
| */ |
| |
| package com.gemstone.gemfire.internal.cache.tier.sockets; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.io.EOFException; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.lang.reflect.Method; |
| import java.math.BigInteger; |
| import java.net.Socket; |
| import java.security.Key; |
| import java.security.KeyFactory; |
| import java.security.KeyPair; |
| import java.security.KeyPairGenerator; |
| import java.security.KeyStore; |
| import java.security.Principal; |
| import java.security.PrivateKey; |
| import java.security.PublicKey; |
| import java.security.SecureRandom; |
| import java.security.Signature; |
| import java.security.cert.Certificate; |
| import java.security.cert.X509Certificate; |
| import java.security.spec.X509EncodedKeySpec; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| |
| import javax.crypto.Cipher; |
| import javax.crypto.KeyAgreement; |
| import javax.crypto.SecretKey; |
| import javax.crypto.spec.DHParameterSpec; |
| import javax.crypto.spec.IvParameterSpec; |
| import javax.crypto.spec.SecretKeySpec; |
| import javax.net.ssl.SSLSocket; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import com.gemstone.gemfire.CancelCriterion; |
| import com.gemstone.gemfire.DataSerializer; |
| import com.gemstone.gemfire.InternalGemFireException; |
| import com.gemstone.gemfire.cache.GatewayConfigurationException; |
| import com.gemstone.gemfire.cache.client.PoolFactory; |
| import com.gemstone.gemfire.cache.client.ServerRefusedConnectionException; |
| import com.gemstone.gemfire.cache.client.internal.Connection; |
| import com.gemstone.gemfire.distributed.DistributedMember; |
| import com.gemstone.gemfire.distributed.DistributedSystem; |
| import com.gemstone.gemfire.distributed.internal.DM; |
| import com.gemstone.gemfire.distributed.internal.DistributionConfig; |
| import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem; |
| import com.gemstone.gemfire.distributed.internal.LonerDistributionManager; |
| import com.gemstone.gemfire.distributed.internal.ServerLocation; |
| import com.gemstone.gemfire.distributed.internal.membership.InternalDistributedMember; |
| import com.gemstone.gemfire.internal.ClassLoadUtil; |
| import com.gemstone.gemfire.internal.HeapDataOutputStream; |
| import com.gemstone.gemfire.internal.InternalDataSerializer; |
| import com.gemstone.gemfire.internal.InternalInstantiator; |
| import com.gemstone.gemfire.internal.SocketUtils; |
| import com.gemstone.gemfire.internal.Version; |
| import com.gemstone.gemfire.internal.VersionedDataInputStream; |
| import com.gemstone.gemfire.internal.VersionedDataOutputStream; |
| import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; |
| import com.gemstone.gemfire.internal.cache.tier.Acceptor; |
| import com.gemstone.gemfire.internal.cache.tier.ClientHandShake; |
| import com.gemstone.gemfire.internal.cache.tier.ConnectionProxy; |
| import com.gemstone.gemfire.internal.i18n.LocalizedStrings; |
| import com.gemstone.gemfire.internal.logging.InternalLogWriter; |
| import com.gemstone.gemfire.internal.logging.LogService; |
| import com.gemstone.gemfire.pdx.internal.PeerTypeRegistration; |
| import com.gemstone.gemfire.security.AuthInitialize; |
| import com.gemstone.gemfire.security.AuthenticationFailedException; |
| import com.gemstone.gemfire.security.AuthenticationRequiredException; |
| import com.gemstone.gemfire.security.Authenticator; |
| import com.gemstone.gemfire.security.GemFireSecurityException; |
| |
| public class HandShake implements ClientHandShake |
| { |
| private static final Logger logger = LogService.getLogger(); |
| |
| protected static final byte REPLY_OK = (byte)59; |
| |
| protected static final byte REPLY_REFUSED = (byte)60; |
| |
| protected static final byte REPLY_INVALID = (byte)61; |
| |
| protected static final byte REPLY_EXCEPTION_AUTHENTICATION_REQUIRED = (byte)62; |
| |
| protected static final byte REPLY_EXCEPTION_AUTHENTICATION_FAILED = (byte)63; |
| |
| protected static final byte REPLY_EXCEPTION_DUPLICATE_DURABLE_CLIENT = (byte)64; |
| |
| protected static final byte REPLY_WAN_CREDENTIALS = (byte)65; |
| |
| protected static final byte REPLY_AUTH_NOT_REQUIRED = (byte)66; |
| |
| private byte code; |
| private int clientReadTimeout = PoolFactory.DEFAULT_READ_TIMEOUT; |
| |
| private boolean isRead = false; |
| protected final DistributedSystem system; |
| |
| /** Singleton for client side */ |
| // Client has no more a singleton handShake instance. Now each connection will |
| // have its own handShake instance. |
| private static HandShake handshake; |
| |
| final protected ClientProxyMembershipID id; |
| |
| private Properties credentials; |
| |
| private Version clientVersion; |
| |
| /** |
| * Used at client side, indicates whether the 'delta-propagation' property is |
| * enabled on the DS this client is connected to. This variable is used to |
| * decide whether to send delta bytes or full value to the server for a |
| * delta-update operation. |
| */ |
| private static boolean deltaEnabledOnServer = true; |
| |
| // Security mode flags |
| |
| /** No credentials being sent */ |
| public static final byte CREDENTIALS_NONE = (byte)0; |
| |
| /** Credentials being sent without encryption on the wire */ |
| public static final byte CREDENTIALS_NORMAL = (byte)1; |
| |
| /** Credentials being sent with Diffie-Hellman key encryption */ |
| public static final byte CREDENTIALS_DHENCRYPT = (byte)2; |
| |
| public static final byte SECURITY_MULTIUSER_NOTIFICATIONCHANNEL = (byte)3; |
| |
| private byte appSecureMode = (byte)0; |
| |
| private PublicKey clientPublicKey = null; |
| |
| private String clientSKAlgo = null; |
| |
| private boolean multiuserSecureMode = false; |
| |
| // Parameters for the Diffie-Hellman key exchange |
| private static final BigInteger dhP = new BigInteger( |
| "13528702063991073999718992897071702177131142188276542919088770094024269" |
| + "73079899070080419278066109785292538223079165925365098181867673946" |
| + "34756714063947534092593553024224277712367371302394452615862654308" |
| + "11180902979719649450105660478776364198726078338308557022096810447" |
| + "3500348898008043285865193451061481841186553"); |
| |
| private static final BigInteger dhG = new BigInteger( |
| "13058345680719715096166513407513969537624553636623932169016704425008150" |
| + "56576152779768716554354314319087014857769741104157332735258102835" |
| + "93126577393912282416840649805564834470583437473176415335737232689" |
| + "81480201869671811010996732593655666464627559582258861254878896534" |
| + "1273697569202082715873518528062345259949959"); |
| |
| private static final int dhL = 1023; |
| |
| private static PrivateKey dhPrivateKey = null; |
| |
| private static PublicKey dhPublicKey = null; |
| |
| private static String dhSKAlgo = null; |
| |
| // Members for server authentication using digital signature |
| |
| private static String certificateFilePath = null; |
| |
| private static HashMap certificateMap = null; |
| |
| private static String privateKeyAlias = null; |
| |
| private static String privateKeySubject = null; |
| |
| private static PrivateKey privateKeyEncrypt = null; |
| |
| private static String privateKeySignAlgo = null; |
| |
| private static SecureRandom random = null; |
| |
| public static final String PUBLIC_KEY_FILE_PROP = "security-client-kspath"; |
| |
| public static final String PUBLIC_KEY_PASSWD_PROP = "security-client-kspasswd"; |
| |
| public static final String PRIVATE_KEY_FILE_PROP = "security-server-kspath"; |
| |
| public static final String PRIVATE_KEY_ALIAS_PROP = "security-server-ksalias"; |
| |
| public static final String PRIVATE_KEY_PASSWD_PROP = "security-server-kspasswd"; |
| |
| /** @since 5.7 */ |
| public static final byte CONFLATION_DEFAULT = 0; |
| /** @since 5.7 */ |
| public static final byte CONFLATION_ON = 1; |
| /** @since 5.7 */ |
| public static final byte CONFLATION_OFF = 2; |
| /** @since 5.7 */ |
| private byte clientConflation = CONFLATION_DEFAULT; |
| |
| /** @since 6.0.3 |
| * List of per client property override bits. |
| */ |
| private byte[] overrides = null; |
| |
| /** |
| * Test hooks for per client conflation |
| * @since 5.7 |
| */ |
| public static byte clientConflationForTesting = 0; |
| public static boolean setClientConflationForTesting = false; |
| |
| /** |
| * Test hook for client version support |
| * @since 5.7 |
| */ |
| private static Version currentClientVersion = ConnectionProxy.VERSION; |
| /** |
| * Another test hook, holding a version ordinal that is higher than CURRENT |
| */ |
| private static short overrideClientVersion = -1; |
| |
| /** Constructor used by server side connection */ |
| public HandShake(Socket sock, int timeout, DistributedSystem sys, |
| Version clientVersion, byte communicationMode) throws IOException, |
| AuthenticationRequiredException { |
| this.clientVersion = clientVersion; |
| this.system = sys; |
| //SocketChannel sc = sock.getChannel(); |
| /*if (sc != null) { |
| } else*/ { |
| int soTimeout = -1; |
| try { |
| soTimeout = sock.getSoTimeout(); |
| sock.setSoTimeout(timeout); |
| InputStream is = SocketUtils.getInputStream(sock);//sock.getInputStream(); |
| int valRead = is.read(); |
| //this.code = (byte)is.read(); |
| if (valRead == -1) { |
| throw new EOFException(LocalizedStrings.HandShake_HANDSHAKE_EOF_REACHED_BEFORE_CLIENT_CODE_COULD_BE_READ.toLocalizedString()); |
| } |
| this.code = (byte)valRead; |
| if (this.code != REPLY_OK) { |
| throw new IOException(LocalizedStrings.HandShake_HANDSHAKE_REPLY_CODE_IS_NOT_OK.toLocalizedString()); |
| } |
| try { |
| DataInputStream dis = new DataInputStream(is); |
| DataOutputStream dos = new DataOutputStream(SocketUtils.getOutputStream(sock));//sock.getOutputStream()); |
| this.clientReadTimeout = dis.readInt(); |
| if (clientVersion.compareTo(Version.CURRENT) < 0) { |
| // versioned streams allow object serialization code to deal with older clients |
| dis = new VersionedDataInputStream(dis, clientVersion); |
| dos = new VersionedDataOutputStream(dos, clientVersion); |
| } |
| this.id = ClientProxyMembershipID.readCanonicalized(dis); |
| // Note: credentials should always be the last piece in handshake for |
| // Diffie-Hellman key exchange to work |
| String authenticator = this.system.getProperties().getProperty( |
| DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME); |
| if (clientVersion.compareTo(Version.GFE_603) >= 0) { |
| setOverrides(new byte[] { dis.readByte() }); |
| } else { |
| setClientConflation(dis.readByte()); |
| } |
| //Hitesh |
| if (this.clientVersion.compareTo(Version.GFE_65) < 0 |
| || communicationMode == Acceptor.GATEWAY_TO_GATEWAY) { |
| this.credentials = readCredentials(dis, dos, authenticator, sys); |
| } else { |
| this.credentials = this |
| .readCredential(dis, dos, authenticator, sys); |
| } |
| } catch(IOException ioe) { |
| this.code = -2; |
| throw ioe; |
| } catch(ClassNotFoundException cnfe) { |
| this.code = -3; |
| throw new IOException(LocalizedStrings.HandShake_CLIENTPROXYMEMBERSHIPID_CLASS_COULD_NOT_BE_FOUND_WHILE_DESERIALIZING_THE_OBJECT.toLocalizedString()); |
| } |
| } finally { |
| if (soTimeout != -1) { |
| try { |
| sock.setSoTimeout(soTimeout); |
| } |
| catch (IOException ignore) { |
| } |
| } |
| } |
| } |
| } |
| |
| public final Version getClientVersion() { |
| return this.clientVersion; |
| } |
| |
| //private void initSingleton(DistributedSystem sys) { |
| // id = ClientProxyMembershipID.getNewProxyMembership(); |
| // this.system = sys; |
| // this.code = REPLY_OK; |
| //} |
| |
| public HandShake(ClientProxyMembershipID id, DistributedSystem sys) { |
| this.id = id; |
| this.code = REPLY_OK; |
| this.system = sys; |
| setOverrides(); |
| this.credentials = null; |
| } |
| |
| public void updateProxyID(InternalDistributedMember idm) { |
| this.id.updateID(idm); |
| } |
| |
| public HandShake(HandShake handShake) { |
| this.appSecureMode = handShake.appSecureMode; |
| this.clientConflation = handShake.clientConflation; |
| this.clientPublicKey = null; |
| this.clientReadTimeout = handShake.clientReadTimeout; |
| this.clientSKAlgo = null; |
| this.clientVersion = handShake.clientVersion; |
| this.code = handShake.code; |
| this.credentials = handShake.credentials; |
| this.isRead = handShake.isRead; |
| this.multiuserSecureMode = handShake.multiuserSecureMode; |
| this.overrides = handShake.overrides; |
| this.system = handShake.system; |
| this.id = handShake.id; |
| //create new one |
| this._decrypt = null; |
| this._encrypt = null; |
| } |
| |
| /*private void read(DataInputStream dis,byte[] toFill) throws IOException { |
| /* this.code = (byte) in.read(); |
| if (this.code == -1) { |
| throw new IOException(LocalizedStrings.HandShake_HANDSHAKE_READ_AT_END_OF_STREAM.toLocalizedString()); |
| } |
| if (this.code != REPLY_OK) { |
| throw new IOException(LocalizedStrings.HandShake_HANDSHAKE_REPLY_CODE_IS_NOT_OK.toLocalizedString()); |
| } |
| try { |
| ObjectInput in = new ObjectInputStream(is); |
| this.id = ClientProxyMembershipID.readCanonicalized(in); |
| } catch(IOException ioe) { |
| this.code = -2; |
| throw ioe; |
| } catch(ClassNotFoundException cnfe) { |
| this.code = -3; |
| IOException e = new IOException(LocalizedStrings.HandShake_ERROR_DESERIALIZING_HANDSHAKE.toLocalizedString()); |
| e.initCause(cnfe); |
| throw e; |
| } |
| } |
| finally { |
| synchronized (this) { |
| this.isRead = true; |
| } |
| } |
| }*/ |
| |
| //used by the client side |
| private byte setClientConflation() { |
| byte result = CONFLATION_DEFAULT; |
| |
| String clientConflationValue = this.system.getProperties().getProperty( |
| DistributionConfig.CLIENT_CONFLATION_PROP_NAME); |
| if (DistributionConfig.CLIENT_CONFLATION_PROP_VALUE_ON |
| .equalsIgnoreCase(clientConflationValue)) { |
| result = CONFLATION_ON; |
| } |
| else |
| if (DistributionConfig.CLIENT_CONFLATION_PROP_VALUE_OFF |
| .equalsIgnoreCase(clientConflationValue)) { |
| result = CONFLATION_OFF; |
| } |
| return result; |
| } |
| |
| // used by the server side |
| private void setClientConflation(byte value) { |
| this.clientConflation = value; |
| switch (this.clientConflation) { |
| case CONFLATION_DEFAULT: |
| case CONFLATION_OFF: |
| case CONFLATION_ON: |
| break; |
| default: |
| throw new IllegalArgumentException("Illegal clientConflation"); |
| } |
| } |
| |
| // used by the client side |
| private void setOverrides() { |
| this.clientConflation = setClientConflation(); |
| |
| // As of May 2009 ( GFE 6.0 ): |
| // Note that this.clientVersion is used by server side for accepting |
| // handshakes. |
| // Client side handshake code uses this.currentClientVersion which can be |
| // set via tests. |
| if (HandShake.currentClientVersion.compareTo(Version.GFE_603) >= 0) { |
| byte override = 0; |
| /* |
| override = this.notifyBySubscriptionOverride; |
| override = (byte)((override << 2) | this.removeUnresponsiveClientOverride); |
| override = (byte)((override << 2) | this.clientConflation); |
| */ |
| override = this.clientConflation; |
| this.overrides = new byte[] { override }; |
| } |
| } |
| |
| // used by the server side |
| private void setOverrides(byte[] values) { |
| byte override = values[0]; |
| setClientConflation(((byte)(override & 0x03))); |
| /* |
| override = (byte)(override >>> 2); |
| setRemoveUnresponsiveClientOverride(((byte)(override & 0x03))); |
| override = (byte)(override >>> 2); |
| setNotifyBySubscriptionOverride(((byte)(override & 0x03))); |
| */ |
| } |
| |
| // used by CacheClientNotifier's handshake reading code |
| public static byte[] extractOverrides(byte[] values) { |
| byte override = values[0]; |
| byte[] overrides = new byte[1]; |
| for (int item = 0; item < overrides.length; item++) { |
| overrides[item] = (byte)(override & 0x03); |
| override = (byte)(override >>> 2); |
| } |
| return overrides; |
| } |
| |
| public static void setVersionForTesting(short ver) { |
| if (ver > Version.CURRENT_ORDINAL) { |
| overrideClientVersion = ver; |
| } else { |
| currentClientVersion = Version.fromOrdinalOrCurrent(ver); |
| overrideClientVersion = -1; |
| } |
| } |
| |
| public byte write(DataOutputStream dos, DataInputStream dis, byte communicationMode, int replyCode, |
| int readTimeout, List ports, Properties p_credentials, DistributedMember member, boolean isCallbackConnection) |
| throws IOException { |
| HeapDataOutputStream hdos = new HeapDataOutputStream(32, Version.CURRENT); |
| byte acceptanceCode = -1; |
| try { |
| hdos.writeByte(communicationMode); |
| if (overrideClientVersion > 0) { |
| // for testing |
| Version.writeOrdinal(hdos, overrideClientVersion, true); |
| } else { |
| Version.writeOrdinal(hdos, currentClientVersion.ordinal(), true); |
| } |
| |
| hdos.writeByte(replyCode); |
| if (ports != null) { |
| hdos.writeInt(ports.size()); |
| for (int i = 0; i < ports.size(); i++) { |
| hdos.writeInt(Integer.parseInt((String)ports.get(i))); |
| } |
| } |
| else { |
| hdos.writeInt(readTimeout); |
| } |
| DataSerializer.writeObject(this.id, hdos); |
| |
| if (currentClientVersion.compareTo(Version.GFE_603) >= 0) { |
| for (int bytes = 0; bytes < this.overrides.length; bytes++) { |
| hdos.writeByte(this.overrides[bytes]); |
| } |
| } else { |
| // write the client conflation setting byte |
| if (setClientConflationForTesting) { |
| hdos.writeByte(clientConflationForTesting); |
| } |
| else { |
| hdos.writeByte(this.clientConflation); |
| } |
| } |
| |
| if (isCallbackConnection |
| || communicationMode == Acceptor.GATEWAY_TO_GATEWAY) { |
| if (isCallbackConnection && this.multiuserSecureMode |
| && communicationMode != Acceptor.GATEWAY_TO_GATEWAY) { |
| hdos.writeByte(SECURITY_MULTIUSER_NOTIFICATIONCHANNEL); |
| hdos.flush(); |
| dos.write(hdos.toByteArray()); |
| dos.flush(); |
| } else { |
| writeCredentials(dos, dis, p_credentials, ports != null, member, hdos); |
| } |
| } else { |
| String authInitMethod = this.system.getProperties().getProperty( |
| DistributionConfig.SECURITY_CLIENT_AUTH_INIT_NAME); |
| acceptanceCode = writeCredential(dos, dis, authInitMethod, |
| ports != null, member, hdos); |
| } |
| } |
| finally { |
| hdos.close(); |
| } |
| return acceptanceCode; |
| } |
| |
| public void writeCredentials(DataOutputStream dos, DataInputStream dis, |
| Properties p_credentials, boolean isNotification, DistributedMember member) |
| throws IOException, GemFireSecurityException { |
| HeapDataOutputStream hdos = new HeapDataOutputStream(32, Version.CURRENT); |
| try { |
| writeCredentials(dos, dis, p_credentials, isNotification, member, hdos); |
| } |
| finally { |
| hdos.close(); |
| } |
| } |
| |
| /** |
| * |
| * This assumes that authentication is the last piece of info in handshake |
| * |
| * @param dos |
| * @param dis |
| * @param p_credentials |
| * @param isNotification |
| * @param member |
| * @param heapdos stream to append data to. |
| * @throws IOException |
| * @throws GemFireSecurityException |
| */ |
| public void writeCredentials(DataOutputStream dos, DataInputStream dis, |
| Properties p_credentials, boolean isNotification, DistributedMember member, |
| HeapDataOutputStream heapdos) |
| throws IOException, GemFireSecurityException { |
| |
| if (p_credentials == null) { |
| // No credentials indicator |
| heapdos.writeByte(CREDENTIALS_NONE); |
| heapdos.flush(); |
| dos.write(heapdos.toByteArray()); |
| dos.flush(); |
| return; |
| } |
| |
| if (dhSKAlgo == null || dhSKAlgo.length() == 0) { |
| // Normal credentials without encryption indicator |
| heapdos.writeByte(CREDENTIALS_NORMAL); |
| DataSerializer.writeProperties(p_credentials, heapdos); |
| heapdos.flush(); |
| dos.write(heapdos.toByteArray()); |
| dos.flush(); |
| return; |
| } |
| |
| try { |
| InternalLogWriter securityLogWriter = (InternalLogWriter)this.system.getSecurityLogWriter(); |
| securityLogWriter.fine("HandShake: using Diffie-Hellman key exchange with algo " + dhSKAlgo); |
| boolean requireAuthentication = (certificateFilePath != null && certificateFilePath |
| .length() > 0); |
| if (requireAuthentication) { |
| securityLogWriter |
| .fine("HandShake: server authentication using digital " |
| + "signature required"); |
| } |
| // Credentials with encryption indicator |
| heapdos.writeByte(CREDENTIALS_DHENCRYPT); |
| heapdos.writeBoolean(requireAuthentication); |
| // Send the symmetric encryption algorithm name |
| DataSerializer.writeString(dhSKAlgo, heapdos); |
| // Send the DH public key |
| byte[] keyBytes = dhPublicKey.getEncoded(); |
| DataSerializer.writeByteArray(keyBytes, heapdos); |
| byte[] clientChallenge = null; |
| if (requireAuthentication) { |
| // Authentication of server should be with the client supplied |
| // challenge |
| clientChallenge = new byte[64]; |
| random.nextBytes(clientChallenge); |
| DataSerializer.writeByteArray(clientChallenge, heapdos); |
| } |
| heapdos.flush(); |
| dos.write(heapdos.toByteArray()); |
| dos.flush(); |
| |
| // Expect the alias and signature in the reply |
| byte acceptanceCode = dis.readByte(); |
| if (acceptanceCode != REPLY_OK |
| && acceptanceCode != REPLY_AUTH_NOT_REQUIRED) { |
| // Ignore the useless data |
| dis.readByte(); |
| dis.readInt(); |
| if (!isNotification) { |
| DataSerializer.readByteArray(dis); |
| } |
| readMessage(dis, dos, acceptanceCode, member); |
| } |
| else |
| if (acceptanceCode == REPLY_OK) { |
| // Get the public key of the other side |
| keyBytes = DataSerializer.readByteArray(dis); |
| if (requireAuthentication) { |
| String subject = DataSerializer.readString(dis); |
| byte[] signatureBytes = DataSerializer.readByteArray(dis); |
| if (!certificateMap.containsKey(subject)) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_HANDSHAKE_FAILED_TO_FIND_PUBLIC_KEY_FOR_SERVER_WITH_SUBJECT_0.toLocalizedString(subject)); |
| } |
| |
| // Check the signature with the public key |
| X509Certificate cert = (X509Certificate)certificateMap |
| .get(subject); |
| Signature sig = Signature.getInstance(cert.getSigAlgName()); |
| sig.initVerify(cert); |
| sig.update(clientChallenge); |
| // Check the challenge string |
| if (!sig.verify(signatureBytes)) { |
| throw new AuthenticationFailedException("Mismatch in client " |
| + "challenge bytes. Malicious server?"); |
| } |
| securityLogWriter.fine("HandShake: Successfully verified the " |
| + "digital signature from server"); |
| } |
| |
| byte[] challenge = DataSerializer.readByteArray(dis); |
| X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); |
| KeyFactory keyFact = KeyFactory.getInstance("DH"); |
| //PublicKey pubKey = keyFact.generatePublic(x509KeySpec); |
| this.clientPublicKey = keyFact.generatePublic(x509KeySpec); |
| |
| |
| |
| HeapDataOutputStream hdos = new HeapDataOutputStream(Version.CURRENT); |
| try { |
| DataSerializer.writeProperties(p_credentials, hdos); |
| // Also add the challenge string |
| DataSerializer.writeByteArray(challenge, hdos); |
| |
| // byte[] encBytes = encrypt.doFinal(hdos.toByteArray()); |
| byte[] encBytes = encryptBytes(hdos.toByteArray(), getEncryptCipher(dhSKAlgo, this.clientPublicKey)); |
| DataSerializer.writeByteArray(encBytes, dos); |
| } |
| finally { |
| hdos.close(); |
| } |
| } |
| } |
| catch (IOException ex) { |
| throw ex; |
| } |
| catch (GemFireSecurityException ex) { |
| throw ex; |
| } |
| catch (Exception ex) { |
| throw new AuthenticationFailedException( |
| "HandShake failed in Diffie-Hellman key exchange", ex); |
| } |
| dos.flush(); |
| } |
| |
| /** |
| * This method writes what readCredential() method expects to read. (Note the |
| * use of singular credential). It is similar to writeCredentials(), except |
| * that it doesn't write credential-properties. |
| * TODO (ashetkar) A better name. |
| * TODO (ashetkar) Could be merged with existing writeCredentials(). |
| * |
| * @param dos |
| * @param dis |
| * @param authInit |
| * @param isNotification |
| * @param member |
| * @param heapdos |
| * @throws IOException |
| * @throws GemFireSecurityException |
| */ |
| public byte writeCredential(DataOutputStream dos, DataInputStream dis, |
| String authInit, boolean isNotification, DistributedMember member, |
| HeapDataOutputStream heapdos) |
| throws IOException, GemFireSecurityException { |
| |
| if (!this.multiuserSecureMode && (authInit == null || authInit.length() == 0)) { |
| // No credentials indicator |
| heapdos.writeByte(CREDENTIALS_NONE); |
| heapdos.flush(); |
| dos.write(heapdos.toByteArray()); |
| dos.flush(); |
| return -1; |
| } |
| |
| if (dhSKAlgo == null || dhSKAlgo.length() == 0) { |
| // Normal credentials without encryption indicator |
| heapdos.writeByte(CREDENTIALS_NORMAL); |
| this.appSecureMode = CREDENTIALS_NORMAL; |
| // DataSerializer.writeProperties(p_credentials, heapdos); |
| heapdos.flush(); |
| dos.write(heapdos.toByteArray()); |
| dos.flush(); |
| return -1; |
| } |
| byte acceptanceCode = -1; |
| try { |
| InternalLogWriter securityLogWriter = (InternalLogWriter)this.system.getSecurityLogWriter(); |
| securityLogWriter.fine("HandShake: using Diffie-Hellman key exchange with algo " + dhSKAlgo); |
| boolean requireAuthentication = (certificateFilePath != null && certificateFilePath |
| .length() > 0); |
| if (requireAuthentication) { |
| securityLogWriter |
| .fine("HandShake: server authentication using digital " |
| + "signature required"); |
| } |
| // Credentials with encryption indicator |
| heapdos.writeByte(CREDENTIALS_DHENCRYPT); |
| this.appSecureMode = CREDENTIALS_DHENCRYPT; |
| heapdos.writeBoolean(requireAuthentication); |
| // Send the symmetric encryption algorithm name |
| DataSerializer.writeString(dhSKAlgo, heapdos); |
| // Send the DH public key |
| byte[] keyBytes = dhPublicKey.getEncoded(); |
| DataSerializer.writeByteArray(keyBytes, heapdos); |
| byte[] clientChallenge = null; |
| if (requireAuthentication) { |
| // Authentication of server should be with the client supplied |
| // challenge |
| clientChallenge = new byte[64]; |
| random.nextBytes(clientChallenge); |
| DataSerializer.writeByteArray(clientChallenge, heapdos); |
| } |
| heapdos.flush(); |
| dos.write(heapdos.toByteArray()); |
| dos.flush(); |
| |
| // Expect the alias and signature in the reply |
| acceptanceCode = dis.readByte(); |
| if (acceptanceCode != REPLY_OK |
| && acceptanceCode != REPLY_AUTH_NOT_REQUIRED) { |
| // Ignore the useless data |
| dis.readByte(); |
| dis.readInt(); |
| if (!isNotification) { |
| DataSerializer.readByteArray(dis); |
| } |
| readMessage(dis, dos, acceptanceCode, member); |
| } |
| else |
| if (acceptanceCode == REPLY_OK) { |
| // Get the public key of the other side |
| keyBytes = DataSerializer.readByteArray(dis); |
| if (requireAuthentication) { |
| String subject = DataSerializer.readString(dis); |
| byte[] signatureBytes = DataSerializer.readByteArray(dis); |
| if (!certificateMap.containsKey(subject)) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_HANDSHAKE_FAILED_TO_FIND_PUBLIC_KEY_FOR_SERVER_WITH_SUBJECT_0.toLocalizedString(subject)); |
| } |
| |
| // Check the signature with the public key |
| X509Certificate cert = (X509Certificate)certificateMap |
| .get(subject); |
| Signature sig = Signature.getInstance(cert.getSigAlgName()); |
| sig.initVerify(cert); |
| sig.update(clientChallenge); |
| // Check the challenge string |
| if (!sig.verify(signatureBytes)) { |
| throw new AuthenticationFailedException("Mismatch in client " |
| + "challenge bytes. Malicious server?"); |
| } |
| securityLogWriter.fine("HandShake: Successfully verified the " |
| + "digital signature from server"); |
| } |
| |
| // Read server challenge bytes |
| byte[] serverChallenge = DataSerializer.readByteArray(dis); |
| X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); |
| KeyFactory keyFact = KeyFactory.getInstance("DH"); |
| // PublicKey pubKey = keyFact.generatePublic(x509KeySpec); |
| this.clientPublicKey = keyFact.generatePublic(x509KeySpec); |
| |
| HeapDataOutputStream hdos = new HeapDataOutputStream(Version.CURRENT); |
| try { |
| // Add the challenge string |
| DataSerializer.writeByteArray(serverChallenge, hdos); |
| // byte[] encBytes = encrypt.doFinal(hdos.toByteArray()); |
| byte[] encBytes = encryptBytes(hdos.toByteArray(), getEncryptCipher(dhSKAlgo, this.clientPublicKey)); |
| DataSerializer.writeByteArray(encBytes, dos); |
| } |
| finally { |
| hdos.close(); |
| } |
| } |
| } |
| catch (IOException ex) { |
| throw ex; |
| } |
| catch (GemFireSecurityException ex) { |
| throw ex; |
| } |
| catch (Exception ex) { |
| throw new AuthenticationFailedException( |
| "HandShake failed in Diffie-Hellman key exchange", ex); |
| } |
| dos.flush(); |
| return acceptanceCode; |
| } |
| |
| public byte [] encryptBytes(byte[] data) throws Exception |
| { |
| if( this.appSecureMode == CREDENTIALS_DHENCRYPT) { |
| String algo = null; |
| if (this.clientSKAlgo != null) { |
| algo = this.clientSKAlgo; |
| } else { |
| algo = dhSKAlgo; |
| } |
| return encryptBytes(data, getEncryptCipher(algo, this.clientPublicKey)); |
| } else { |
| return data; |
| } |
| } |
| |
| static public byte[] encryptBytes(byte[] data, Cipher encrypt) |
| throws Exception{ |
| |
| |
| try{ |
| byte[] encBytes = encrypt.doFinal(data); |
| return encBytes; |
| } catch (Exception ex) { |
| throw ex; |
| } |
| } |
| |
| private Cipher _encrypt; |
| |
| private Cipher getEncryptCipher(String dhSKAlgo, PublicKey publicKey) |
| throws Exception{ |
| try { |
| if(_encrypt == null) { |
| KeyAgreement ka = KeyAgreement.getInstance("DH"); |
| ka.init(dhPrivateKey); |
| ka.doPhase(publicKey, true); |
| |
| Cipher encrypt; |
| |
| int keysize = getKeySize(dhSKAlgo); |
| int blocksize = getBlockSize(dhSKAlgo); |
| |
| if (keysize == -1 || blocksize == -1) { |
| SecretKey sKey = ka.generateSecret(dhSKAlgo); |
| encrypt = Cipher.getInstance(dhSKAlgo); |
| encrypt.init(Cipher.ENCRYPT_MODE, sKey); |
| } |
| else { |
| String dhAlgoStr = getDhAlgoStr(dhSKAlgo); |
| |
| byte[] sKeyBytes = ka.generateSecret(); |
| SecretKeySpec sks = new SecretKeySpec(sKeyBytes, 0, keysize, dhAlgoStr); |
| IvParameterSpec ivps = new IvParameterSpec(sKeyBytes, keysize, blocksize); |
| |
| encrypt = Cipher.getInstance(dhAlgoStr + "/CBC/PKCS5Padding"); |
| encrypt.init(Cipher.ENCRYPT_MODE, sks, ivps); |
| } |
| _encrypt = encrypt; |
| } |
| }catch(Exception ex) { |
| throw ex; |
| } |
| return _encrypt; |
| } |
| |
| //This assumes that authentication is the last piece of info in handshake |
| public Properties readCredential(DataInputStream dis, |
| DataOutputStream dos, String authenticator, DistributedSystem system) |
| throws GemFireSecurityException, IOException { |
| |
| Properties credentials = null; |
| boolean requireAuthentication = (authenticator != null && authenticator |
| .length() > 0); |
| try { |
| byte secureMode = dis.readByte(); |
| if (secureMode == CREDENTIALS_NONE) { |
| // when server is configured with authenticator, new joiner must |
| // pass its credentials. |
| if (requireAuthentication) { |
| throw new AuthenticationRequiredException( |
| LocalizedStrings.HandShake_NO_SECURITY_PROPERTIES_ARE_PROVIDED |
| .toLocalizedString()); |
| } |
| } |
| else if (secureMode == CREDENTIALS_NORMAL) { |
| this.appSecureMode = CREDENTIALS_NORMAL; |
| /*if (requireAuthentication) { |
| credentials = DataSerializer.readProperties(dis); |
| } |
| else { |
| DataSerializer.readProperties(dis); // ignore the credentials |
| }*/ |
| } |
| else if (secureMode == CREDENTIALS_DHENCRYPT) { |
| this.appSecureMode = CREDENTIALS_DHENCRYPT; |
| boolean sendAuthentication = dis.readBoolean(); |
| InternalLogWriter securityLogWriter = (InternalLogWriter)system.getSecurityLogWriter(); |
| // Get the symmetric encryption algorithm to be used |
| //String skAlgo = DataSerializer.readString(dis); |
| this.clientSKAlgo = DataSerializer.readString(dis); |
| // Get the public key of the other side |
| byte[] keyBytes = DataSerializer.readByteArray(dis); |
| byte[] challenge = null; |
| // PublicKey pubKey = null; |
| if (requireAuthentication) { |
| // Generate PublicKey from encoded form |
| X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); |
| KeyFactory keyFact = KeyFactory.getInstance("DH"); |
| this.clientPublicKey = keyFact.generatePublic(x509KeySpec); |
| |
| // Send the public key to other side |
| keyBytes = dhPublicKey.getEncoded(); |
| challenge = new byte[64]; |
| random.nextBytes(challenge); |
| |
| // If the server has to also authenticate itself then |
| // sign the challenge from client. |
| if (sendAuthentication) { |
| // Get the challenge string from client |
| byte[] clientChallenge = DataSerializer.readByteArray(dis); |
| if (privateKeyEncrypt == null) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_SERVER_PRIVATE_KEY_NOT_AVAILABLE_FOR_CREATING_SIGNATURE.toLocalizedString()); |
| } |
| // Sign the challenge from client and send it to the client |
| Signature sig = Signature.getInstance(privateKeySignAlgo); |
| sig.initSign(privateKeyEncrypt); |
| sig.update(clientChallenge); |
| byte[] signedBytes = sig.sign(); |
| dos.writeByte(REPLY_OK); |
| DataSerializer.writeByteArray(keyBytes, dos); |
| //DataSerializer.writeString(privateKeyAlias, dos); |
| DataSerializer.writeString(privateKeySubject, dos); |
| DataSerializer.writeByteArray(signedBytes, dos); |
| securityLogWriter.fine("HandShake: sent the signed client challenge"); |
| } |
| else { |
| // These two lines should not be moved before the if{} statement in |
| // a common block for both if...then...else parts. This is to handle |
| // the case when an AuthenticationFailedException is thrown by the |
| // if...then part when sending the signature. |
| dos.writeByte(REPLY_OK); |
| DataSerializer.writeByteArray(keyBytes, dos); |
| } |
| // Now send the server challenge |
| DataSerializer.writeByteArray(challenge, dos); |
| securityLogWriter.fine("HandShake: sent the public key and challenge"); |
| dos.flush(); |
| |
| // Read and decrypt the credentials |
| byte[] encBytes = DataSerializer.readByteArray(dis); |
| Cipher c= getDecryptCipher(this.clientSKAlgo, this.clientPublicKey); |
| byte[] credentialBytes = decryptBytes(encBytes, c); |
| ByteArrayInputStream bis = new ByteArrayInputStream(credentialBytes); |
| DataInputStream dinp = new DataInputStream(bis); |
| //credentials = DataSerializer.readProperties(dinp);//Hitesh: we don't send in handshake now |
| byte[] challengeRes = DataSerializer.readByteArray(dinp); |
| // Check the challenge string |
| if (!Arrays.equals(challenge, challengeRes)) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_MISMATCH_IN_CHALLENGE_BYTES_MALICIOUS_CLIENT |
| .toLocalizedString()); |
| } |
| dinp.close(); |
| } |
| else { |
| if (sendAuthentication) { |
| // Read and ignore the client challenge |
| DataSerializer.readByteArray(dis); |
| } |
| dos.writeByte(REPLY_AUTH_NOT_REQUIRED); |
| dos.flush(); |
| } |
| } |
| } |
| catch (IOException ex) { |
| throw ex; |
| } |
| catch (GemFireSecurityException ex) { |
| throw ex; |
| } |
| catch (Exception ex) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_FAILURE_IN_READING_CREDENTIALS |
| .toLocalizedString(), |
| ex); |
| } |
| return credentials; |
| } |
| |
| public byte[] decryptBytes(byte[] data) throws Exception |
| { |
| if( this.appSecureMode == CREDENTIALS_DHENCRYPT) { |
| String algo = null; |
| if (this.clientSKAlgo != null) { |
| algo = this.clientSKAlgo; |
| } else { |
| algo = dhSKAlgo; |
| } |
| Cipher c= getDecryptCipher(algo, this.clientPublicKey); |
| return decryptBytes(data, c); |
| } else { |
| return data; |
| } |
| } |
| |
| |
| |
| static public byte[] decryptBytes(byte[] data, Cipher decrypt) |
| throws Exception{ |
| try { |
| byte[] decrptBytes = decrypt.doFinal(data); |
| return decrptBytes; |
| }catch(Exception ex) { |
| throw ex; |
| } |
| } |
| |
| private Cipher _decrypt = null; |
| |
| private Cipher getDecryptCipher( String dhSKAlgo, PublicKey publicKey) |
| throws Exception{ |
| if(_decrypt == null) { |
| try { |
| KeyAgreement ka = KeyAgreement.getInstance("DH"); |
| ka.init(dhPrivateKey); |
| ka.doPhase(publicKey, true); |
| |
| Cipher decrypt; |
| |
| int keysize = getKeySize(dhSKAlgo); |
| int blocksize = getBlockSize(dhSKAlgo); |
| |
| if (keysize == -1 || blocksize == -1) { |
| SecretKey sKey = ka.generateSecret(dhSKAlgo); |
| decrypt = Cipher.getInstance(dhSKAlgo); |
| decrypt.init(Cipher.DECRYPT_MODE, sKey); |
| } |
| else { |
| String algoStr = getDhAlgoStr(dhSKAlgo); |
| |
| byte[] sKeyBytes = ka.generateSecret(); |
| SecretKeySpec sks = new SecretKeySpec(sKeyBytes, 0, keysize, algoStr); |
| IvParameterSpec ivps = new IvParameterSpec(sKeyBytes, keysize, blocksize); |
| |
| decrypt = Cipher.getInstance(algoStr + "/CBC/PKCS5Padding"); |
| decrypt.init(Cipher.DECRYPT_MODE, sks, ivps); |
| } |
| |
| _decrypt = decrypt; |
| }catch(Exception ex) { |
| throw ex; |
| } |
| } |
| return _decrypt; |
| } |
| /** |
| * Populate the available server public keys into a local static HashMap. This |
| * method is not thread safe. |
| */ |
| public static void initCertsMap(Properties props) throws Exception { |
| |
| certificateMap = new HashMap(); |
| certificateFilePath = props.getProperty(PUBLIC_KEY_FILE_PROP); |
| if (certificateFilePath != null && certificateFilePath.length() > 0) { |
| KeyStore ks = KeyStore.getInstance("JKS"); |
| String keyStorePass = props.getProperty(PUBLIC_KEY_PASSWD_PROP); |
| char[] passPhrase = (keyStorePass != null ? keyStorePass.toCharArray() |
| : null); |
| FileInputStream keystorefile = new FileInputStream(certificateFilePath); |
| try { |
| ks.load(keystorefile, passPhrase); |
| } |
| finally { |
| keystorefile.close(); |
| } |
| Enumeration aliases = ks.aliases(); |
| while (aliases.hasMoreElements()) { |
| String alias = (String)aliases.nextElement(); |
| Certificate cert = ks.getCertificate(alias); |
| if (cert instanceof X509Certificate) { |
| String subject = ((X509Certificate)cert).getSubjectDN().getName(); |
| certificateMap.put(subject, cert); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Load the private key of the server. This method is not thread safe. |
| */ |
| public static void initPrivateKey(Properties props) throws Exception { |
| |
| String privateKeyFilePath = props.getProperty(PRIVATE_KEY_FILE_PROP); |
| privateKeyAlias = ""; |
| privateKeyEncrypt = null; |
| if (privateKeyFilePath != null && privateKeyFilePath.length() > 0) { |
| KeyStore ks = KeyStore.getInstance("PKCS12"); |
| privateKeyAlias = props.getProperty(PRIVATE_KEY_ALIAS_PROP); |
| if (privateKeyAlias == null) { |
| privateKeyAlias = ""; |
| } |
| String keyStorePass = props.getProperty(PRIVATE_KEY_PASSWD_PROP); |
| char[] passPhrase = (keyStorePass != null ? keyStorePass.toCharArray() |
| : null); |
| FileInputStream privateKeyFile = new FileInputStream(privateKeyFilePath); |
| try { |
| ks.load(privateKeyFile, passPhrase); |
| } |
| finally { |
| privateKeyFile.close(); |
| } |
| Key key = ks.getKey(privateKeyAlias, passPhrase); |
| Certificate keyCert = ks.getCertificate(privateKeyAlias); |
| if (key instanceof PrivateKey && keyCert instanceof X509Certificate) { |
| privateKeyEncrypt = (PrivateKey)key; |
| privateKeySignAlgo = ((X509Certificate)keyCert).getSigAlgName(); |
| privateKeySubject = ((X509Certificate)keyCert).getSubjectDN().getName(); |
| } |
| } |
| } |
| |
| /** |
| * Initialize the Diffie-Hellman keys. This method is not thread safe |
| */ |
| public static void initDHKeys(DistributionConfig config) throws Exception { |
| |
| dhSKAlgo = config.getSecurityClientDHAlgo(); |
| dhPrivateKey = null; |
| dhPublicKey = null; |
| String authenticator = config.getSecurityClientAuthenticator(); |
| // Initialize the keys when either the host is a client that has |
| // non-blank setting for DH symmetric algo, or this is a server |
| // that has authenticator defined. |
| if ((dhSKAlgo != null && dhSKAlgo.length() > 0) |
| || (authenticator != null && authenticator.length() > 0)) { |
| KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH"); |
| DHParameterSpec dhSpec = new DHParameterSpec(dhP, dhG, dhL); |
| keyGen.initialize(dhSpec); |
| KeyPair keypair = keyGen.generateKeyPair(); |
| |
| // Get the generated public and private keys |
| dhPrivateKey = keypair.getPrivate(); |
| dhPublicKey = keypair.getPublic(); |
| |
| random = new SecureRandom(); |
| // Force the random generator to seed itself. |
| byte[] someBytes = new byte[48]; |
| random.nextBytes(someBytes); |
| } |
| } |
| |
| public void accept(OutputStream out, InputStream in, byte epType, int qSize, |
| byte communicationMode, Principal principal) throws IOException { |
| DataOutputStream dos = new DataOutputStream(out); |
| DataInputStream dis; |
| if (clientVersion.compareTo(Version.CURRENT) < 0) { |
| dis = new VersionedDataInputStream(in, clientVersion); |
| dos = new VersionedDataOutputStream(dos, clientVersion); |
| } else { |
| dis = new DataInputStream(in); |
| } |
| // Write ok reply |
| //TODO:HItesh |
| if (communicationMode == Acceptor.GATEWAY_TO_GATEWAY && principal != null) { |
| dos.writeByte(REPLY_WAN_CREDENTIALS); |
| } |
| else { |
| dos.writeByte(REPLY_OK);//byte 59 |
| } |
| |
| |
| //additional byte of wan site needs to send for Gateway BC |
| if (communicationMode == Acceptor.GATEWAY_TO_GATEWAY) { |
| Version.writeOrdinal(dos, ServerHandShakeProcessor.currentServerVersion.ordinal(), |
| true); |
| } |
| |
| dos.writeByte(epType); |
| dos.writeInt(qSize); |
| |
| // Write the server's member |
| DistributedMember member = this.system.getDistributedMember(); |
| ServerHandShakeProcessor.writeServerMember(member, dos); |
| |
| // Write no message |
| dos.writeUTF(""); |
| |
| // Write delta-propagation property value if this is not WAN. |
| if (communicationMode != Acceptor.GATEWAY_TO_GATEWAY |
| && this.clientVersion.compareTo(Version.GFE_61) >= 0) { |
| dos.writeBoolean(((InternalDistributedSystem)this.system).getConfig() |
| .getDeltaPropagation()); |
| } |
| |
| // Neeraj: Now if the communication mode is GATEWAY_TO_GATEWAY |
| // and principal not equal to null then send the credentials also |
| if (communicationMode == Acceptor.GATEWAY_TO_GATEWAY && principal != null) { |
| sendCredentialsForWan(dos, dis); |
| } |
| |
| // Write the distributed system id if this is a 6.6 or greater client |
| //on the remote side of the gateway |
| if (communicationMode == Acceptor.GATEWAY_TO_GATEWAY |
| && this.clientVersion.compareTo(Version.GFE_66) >= 0 |
| && ServerHandShakeProcessor.currentServerVersion.compareTo(Version.GFE_66) >= 0) { |
| dos.writeByte(((InternalDistributedSystem)this.system) |
| .getDistributionManager().getDistributedSystemId()); |
| } |
| |
| if((communicationMode == Acceptor.GATEWAY_TO_GATEWAY) |
| && this.clientVersion.compareTo(Version.GFE_80) >= 0 |
| && ServerHandShakeProcessor.currentServerVersion.compareTo(Version.GFE_80) >= 0) { |
| int pdxSize = PeerTypeRegistration.getPdxRegistrySize(); |
| dos.writeInt(pdxSize); |
| } |
| |
| // Flush |
| dos.flush(); |
| } |
| |
| /** |
| * Return fake, temporary DistributedMember to represent the other vm this |
| * vm is connecting to |
| * |
| * @param sock the socket this handshake is operating on |
| * @return temporary id to reprent the other vm |
| */ |
| private DistributedMember getDistributedMember(Socket sock) { |
| return new InternalDistributedMember( |
| sock.getInetAddress(), sock.getPort(), false); |
| } |
| |
| public ServerQueueStatus greet(Connection conn, ServerLocation location, byte communicationMode) throws IOException, |
| AuthenticationRequiredException, AuthenticationFailedException, |
| ServerRefusedConnectionException { |
| try { |
| ServerQueueStatus serverQStatus = null; |
| Socket sock = conn.getSocket(); |
| DataOutputStream dos = new DataOutputStream(SocketUtils.getOutputStream(sock));//sock.getOutputStream()); |
| final InputStream in = SocketUtils.getInputStream(sock);//sock.getInputStream(); |
| DataInputStream dis = new DataInputStream(in); |
| DistributedMember member = getDistributedMember(sock); |
| // if running in a loner system, use the new port number in the ID to |
| // help differentiate from other clients |
| DM dm = ((InternalDistributedSystem)this.system).getDistributionManager(); |
| InternalDistributedMember idm = dm.getDistributionManagerId(); |
| synchronized(idm) { |
| if (idm.getPort() == 0 && dm instanceof LonerDistributionManager) { |
| int port = sock.getLocalPort(); |
| ((LonerDistributionManager)dm).updateLonerPort(port); |
| updateProxyID(dm.getDistributionManagerId()); |
| } |
| } |
| if(communicationMode == Acceptor.GATEWAY_TO_GATEWAY) { |
| this.credentials = getCredentials(member); |
| } |
| byte intermediateAcceptanceCode = write(dos, dis, communicationMode, |
| REPLY_OK, this.clientReadTimeout, null, this.credentials, member, |
| false); |
| |
| String authInit = this.system.getProperties().getProperty( |
| DistributionConfig.SECURITY_CLIENT_AUTH_INIT_NAME); |
| if (communicationMode != Acceptor.GATEWAY_TO_GATEWAY |
| && intermediateAcceptanceCode != REPLY_AUTH_NOT_REQUIRED |
| && (authInit != null && authInit.length() != 0)) { |
| location.compareAndSetRequiresCredentials(true); |
| } |
| // Read the acceptance code |
| byte acceptanceCode = dis.readByte(); |
| if (acceptanceCode == (byte)21 && !(sock instanceof SSLSocket)) { |
| // This is likely the case of server setup with SSL and client not using |
| // SSL |
| throw new AuthenticationRequiredException( |
| LocalizedStrings.HandShake_SERVER_EXPECTING_SSL_CONNECTION |
| .toLocalizedString()); |
| } |
| |
| //Successful handshake for GATEWAY_TO_GATEWAY mode sets the peer version in connection |
| if(communicationMode == Acceptor.GATEWAY_TO_GATEWAY && ! |
| (acceptanceCode == REPLY_EXCEPTION_AUTHENTICATION_REQUIRED || |
| acceptanceCode == REPLY_EXCEPTION_AUTHENTICATION_FAILED)) { |
| conn.setWanSiteVersion(Version.readOrdinal(dis)); |
| } |
| |
| // No need to check for return value since DataInputStream already throws |
| // EOFException in case of EOF |
| byte epType = dis.readByte(); |
| int qSize = dis.readInt(); |
| |
| // Read the server member |
| member = readServerMember(dis); |
| serverQStatus = new ServerQueueStatus(epType, qSize,member); |
| |
| // Read the message (if any) |
| readMessage(dis, dos, acceptanceCode, member); |
| |
| // Read delta-propagation property value from server. |
| // [sumedh] Static variable below? Client can connect to different |
| // DSes with different values of this. It shoule be a member variable. |
| if (communicationMode != Acceptor.GATEWAY_TO_GATEWAY |
| && currentClientVersion.compareTo(Version.GFE_61) >= 0) { |
| deltaEnabledOnServer = dis.readBoolean(); |
| } |
| |
| //validate that the remote side has a different distributed system id. |
| if (communicationMode == Acceptor.GATEWAY_TO_GATEWAY |
| && Version.GFE_66.compareTo(conn.getWanSiteVersion()) <= 0 |
| && currentClientVersion.compareTo(Version.GFE_66) >= 0) { |
| int remoteDistributedSystemId = in.read(); |
| int localDistributedSystemId = ((InternalDistributedSystem) system).getDistributionManager().getDistributedSystemId(); |
| if(localDistributedSystemId >= 0 && localDistributedSystemId == remoteDistributedSystemId) { |
| throw new GatewayConfigurationException( |
| "Remote WAN site's distributed system id " |
| + remoteDistributedSystemId |
| + " matches this sites distributed system id " |
| + localDistributedSystemId); |
| } |
| } |
| //Read the PDX registry size from the remote size |
| if(communicationMode == Acceptor.GATEWAY_TO_GATEWAY |
| && Version.GFE_80.compareTo(conn.getWanSiteVersion()) <= 0 |
| && currentClientVersion.compareTo(Version.GFE_80) >= 0) { |
| int remotePdxSize = dis.readInt(); |
| serverQStatus.setPdxSize(remotePdxSize); |
| } |
| |
| return serverQStatus; |
| } |
| catch (IOException ex) { |
| CancelCriterion stopper = this.system.getCancelCriterion(); |
| stopper.checkCancelInProgress(null); |
| throw ex; |
| } |
| } |
| |
| public ServerQueueStatus greetNotifier(Socket sock, boolean isPrimary, ServerLocation location) throws IOException, AuthenticationRequiredException, |
| AuthenticationFailedException, ServerRefusedConnectionException, ClassNotFoundException { |
| ServerQueueStatus sqs = null; |
| try { |
| DataOutputStream dos = new DataOutputStream(SocketUtils.getOutputStream(sock));//sock.getOutputStream()); |
| final InputStream in = SocketUtils.getInputStream(sock);//sock.getInputStream()); |
| DataInputStream dis = new DataInputStream(in); |
| DistributedMember member = getDistributedMember(sock); |
| if (!this.multiuserSecureMode) { |
| this.credentials = getCredentials(member); |
| } |
| byte mode = isPrimary ? Acceptor.PRIMARY_SERVER_TO_CLIENT |
| : Acceptor.SECONDARY_SERVER_TO_CLIENT; |
| write(dos, dis, mode, REPLY_OK, 0, new ArrayList(), this.credentials, |
| member, true); |
| |
| // Wait here for a reply before continuing. This ensures that the client |
| // updater is registered with the server before continuing. |
| byte acceptanceCode = dis.readByte(); |
| if (acceptanceCode == (byte)21 && !(sock instanceof SSLSocket)) { |
| // This is likely the case of server setup with SSL and client not using |
| // SSL |
| throw new AuthenticationRequiredException( |
| LocalizedStrings.HandShake_SERVER_EXPECTING_SSL_CONNECTION.toLocalizedString()); |
| } |
| |
| // No need to check for return value since DataInputStream already throws |
| // EOFException in case of EOF |
| byte qType = dis.readByte(); |
| // read and ignore qSize flag |
| int qSize = dis.readInt(); |
| sqs = new ServerQueueStatus(qType, qSize, member); |
| |
| // Read the message (if any) |
| readMessage(dis, dos, acceptanceCode, member); |
| |
| // [sumedh] nothing more to be done for older clients used in tests |
| // there is a difference in serializer map registration for >= 6.5.1.6 |
| // clients but that is not used in tests |
| if (currentClientVersion.compareTo(Version.GFE_61) < 0) { |
| return sqs; |
| } |
| HashMap instantiatorMap = DataSerializer.readHashMap(dis); |
| for (Iterator itr = instantiatorMap.entrySet().iterator(); itr.hasNext();) { |
| Map.Entry instantiator = (Map.Entry)itr.next(); |
| Integer id = (Integer)instantiator.getKey(); |
| ArrayList instantiatorArguments = (ArrayList)instantiator.getValue(); |
| InternalInstantiator.register((String)instantiatorArguments |
| .get(0), (String)instantiatorArguments.get(1), id, false); |
| } |
| |
| HashMap dataSerializersMap = DataSerializer.readHashMap(dis); |
| for (Iterator itr = dataSerializersMap.entrySet().iterator(); itr.hasNext();) { |
| Map.Entry dataSerializer = (Map.Entry)itr.next(); |
| Integer id = (Integer)dataSerializer.getKey(); |
| InternalDataSerializer.register((String)dataSerializer.getValue(), |
| false, null, null, id); |
| } |
| HashMap<Integer, ArrayList<String>> dsToSupportedClassNames = DataSerializer.readHashMap(dis); |
| InternalDataSerializer.updateSupportedClassesMap(dsToSupportedClassNames); |
| } |
| catch (IOException ex) { |
| CancelCriterion stopper = this.system.getCancelCriterion(); |
| stopper.checkCancelInProgress(null); |
| throw ex; |
| } |
| catch (ClassNotFoundException ex) { |
| CancelCriterion stopper = this.system.getCancelCriterion(); |
| stopper.checkCancelInProgress(null); |
| throw ex; |
| } |
| return sqs; |
| } |
| |
| protected DistributedMember readServerMember(DataInputStream p_dis) throws IOException { |
| |
| byte[] memberBytes = DataSerializer.readByteArray(p_dis); |
| ByteArrayInputStream bais = new ByteArrayInputStream(memberBytes); |
| DataInputStream dis = new DataInputStream(bais); |
| try { |
| return (DistributedMember)DataSerializer.readObject(dis); |
| } |
| catch (EOFException e) { |
| throw e; |
| } |
| catch (Exception e) { |
| throw new InternalGemFireException(LocalizedStrings.HandShake_UNABLE_TO_DESERIALIZE_MEMBER.toLocalizedString(), e); |
| } |
| } |
| |
| protected void readMessage(DataInputStream dis, DataOutputStream dos, byte acceptanceCode, DistributedMember member) |
| throws IOException, AuthenticationRequiredException, |
| AuthenticationFailedException, ServerRefusedConnectionException { |
| |
| String message = dis.readUTF(); |
| if (message.length() == 0 && acceptanceCode != REPLY_WAN_CREDENTIALS) { |
| return; // success |
| } |
| |
| switch (acceptanceCode) { |
| case REPLY_EXCEPTION_AUTHENTICATION_REQUIRED: |
| throw new AuthenticationRequiredException(message); |
| case REPLY_EXCEPTION_AUTHENTICATION_FAILED: |
| throw new AuthenticationFailedException(message); |
| case REPLY_EXCEPTION_DUPLICATE_DURABLE_CLIENT: |
| throw new ServerRefusedConnectionException(member, |
| message); |
| case REPLY_WAN_CREDENTIALS: |
| checkIfAuthenticWanSite(dis, dos, member); |
| break; |
| default: |
| throw new ServerRefusedConnectionException(member, |
| message); |
| } |
| } |
| |
| public byte getCode() |
| { |
| return this.code; |
| } |
| |
| public boolean isRead() |
| { |
| return this.isRead; |
| } |
| |
| public boolean isOK() |
| { |
| return getCode() == REPLY_OK; |
| } |
| |
| public void setClientReadTimeout(int clientReadTimeout) { |
| this.clientReadTimeout = clientReadTimeout; |
| } |
| |
| public int getClientReadTimeout() { |
| return this.clientReadTimeout; |
| } |
| |
| public void setMultiuserSecureMode(boolean bool) { |
| this.multiuserSecureMode = bool; |
| } |
| |
| public boolean isMultiuserSecureMode() { |
| return this.multiuserSecureMode; |
| } |
| |
| /** |
| * Indicates whether some other object is "equal to" this one. |
| * |
| * @param other the reference object with which to compare. |
| * @return true if this object is the same as the obj argument; |
| * false otherwise. |
| */ |
| @Override |
| public boolean equals(Object other) { |
| if (other == this) return true; |
| // if (other == null) return false; |
| if (!(other instanceof HandShake)) return false; |
| final HandShake that = (HandShake) other; |
| |
| /*if (identity != null && identity.length > 0) { |
| for (int i = 0; i < identity.length; i++) { |
| if (this.identity[i] != that.identity[i]) return false; |
| } |
| } |
| if (this.code != that.code) return false; |
| return true;*/ |
| |
| if(this.id.isSameDSMember(that.id) && this.code ==that.code) { |
| return true; |
| } |
| else { |
| return false; |
| } |
| } |
| |
| |
| /** |
| * Returns a hash code for the object. This method is supported for the |
| * benefit of hashtables such as those provided by java.util.Hashtable. |
| * |
| * @return the integer 0 if description is null; otherwise a unique integer. |
| */ |
| @Override |
| public int hashCode() { |
| int result = 17; |
| final int mult = 37; |
| |
| /*if (this.identity != null && this.identity.length > 0) { |
| for (int i = 0; i < this.identity.length; i++) { |
| result = mult * result + (int) this.identity[i]; |
| } |
| }*/ |
| result = this.id.hashCode(); |
| result = mult * result + this.code; |
| |
| return result; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuffer buf = new StringBuffer() |
| .append("HandShake@") |
| .append(System.identityHashCode(this)) |
| .append(" code: ") |
| .append(this.code); |
| if (this.id != null) { |
| buf.append(" identity: "); |
| /*for(int i=0; i<this.identity.length; ++i) { |
| buf.append(this.identity[i]); |
| }*/ |
| buf.append(this.id.toString()); |
| } |
| return buf.toString(); |
| } |
| |
| public ClientProxyMembershipID getMembership() { |
| return this.id; |
| } |
| |
| public static Properties getCredentials(String authInitMethod, |
| Properties securityProperties, DistributedMember server, boolean isPeer, |
| InternalLogWriter logWriter, InternalLogWriter securityLogWriter) |
| throws AuthenticationRequiredException { |
| |
| Properties credentials = null; |
| try { |
| if (authInitMethod != null && authInitMethod.length() > 0) { |
| Method instanceGetter = ClassLoadUtil.methodFromName(authInitMethod); |
| AuthInitialize auth = (AuthInitialize)instanceGetter.invoke(null, |
| (Object[])null); |
| if (auth != null) { |
| auth.init(logWriter, |
| securityLogWriter); |
| try { |
| credentials = auth.getCredentials(securityProperties, server, |
| isPeer); |
| } |
| finally { |
| auth.close(); |
| } |
| } |
| } |
| } |
| catch (GemFireSecurityException ex) { |
| throw ex; |
| } |
| catch (Exception ex) { |
| throw new AuthenticationRequiredException( |
| LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHINITIALIZE_METHOD_0.toLocalizedString(authInitMethod), ex); |
| } |
| return credentials; |
| } |
| |
| private Properties getCredentials(DistributedMember member) { |
| |
| String authInitMethod = this.system.getProperties().getProperty( |
| DistributionConfig.SECURITY_CLIENT_AUTH_INIT_NAME); |
| return getCredentials(authInitMethod, this.system.getSecurityProperties(), |
| member, false, (InternalLogWriter)this.system.getLogWriter(), |
| (InternalLogWriter)this.system.getSecurityLogWriter()); |
| } |
| |
| // This assumes that authentication is the last piece of info in handshake |
| public static Properties readCredentials(DataInputStream dis, |
| DataOutputStream dos, String authenticator, DistributedSystem system) |
| throws GemFireSecurityException, IOException { |
| |
| Properties credentials = null; |
| boolean requireAuthentication = (authenticator != null && authenticator |
| .length() > 0); |
| try { |
| byte secureMode = dis.readByte(); |
| if (secureMode == CREDENTIALS_NONE) { |
| // when server is configured with authenticator, new joiner must |
| // pass its credentials. |
| if (requireAuthentication) { |
| throw new AuthenticationRequiredException( |
| LocalizedStrings.HandShake_NO_SECURITY_PROPERTIES_ARE_PROVIDED |
| .toLocalizedString()); |
| } |
| } |
| else if (secureMode == CREDENTIALS_NORMAL) { |
| if (requireAuthentication) { |
| credentials = DataSerializer.readProperties(dis); |
| } |
| else { |
| DataSerializer.readProperties(dis); // ignore the credentials |
| } |
| } |
| else if (secureMode == CREDENTIALS_DHENCRYPT) { |
| boolean sendAuthentication = dis.readBoolean(); |
| InternalLogWriter securityLogWriter = (InternalLogWriter)system.getSecurityLogWriter(); |
| // Get the symmetric encryption algorithm to be used |
| String skAlgo = DataSerializer.readString(dis); |
| // Get the public key of the other side |
| byte[] keyBytes = DataSerializer.readByteArray(dis); |
| byte[] challenge = null; |
| PublicKey pubKey = null; |
| if (requireAuthentication) { |
| // Generate PublicKey from encoded form |
| X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); |
| KeyFactory keyFact = KeyFactory.getInstance("DH"); |
| pubKey = keyFact.generatePublic(x509KeySpec); |
| |
| // Send the public key to other side |
| keyBytes = dhPublicKey.getEncoded(); |
| challenge = new byte[64]; |
| random.nextBytes(challenge); |
| |
| // If the server has to also authenticate itself then |
| // sign the challenge from client. |
| if (sendAuthentication) { |
| // Get the challenge string from client |
| byte[] clientChallenge = DataSerializer.readByteArray(dis); |
| if (privateKeyEncrypt == null) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_SERVER_PRIVATE_KEY_NOT_AVAILABLE_FOR_CREATING_SIGNATURE.toLocalizedString()); |
| } |
| // Sign the challenge from client and send it to the client |
| Signature sig = Signature.getInstance(privateKeySignAlgo); |
| sig.initSign(privateKeyEncrypt); |
| sig.update(clientChallenge); |
| byte[] signedBytes = sig.sign(); |
| dos.writeByte(REPLY_OK); |
| DataSerializer.writeByteArray(keyBytes, dos); |
| //DataSerializer.writeString(privateKeyAlias, dos); |
| DataSerializer.writeString(privateKeySubject, dos); |
| DataSerializer.writeByteArray(signedBytes, dos); |
| securityLogWriter.fine("HandShake: sent the signed client challenge"); |
| } |
| else { |
| // These two lines should not be moved before the if{} statement in |
| // a common block for both if...then...else parts. This is to handle |
| // the case when an AuthenticationFailedException is thrown by the |
| // if...then part when sending the signature. |
| dos.writeByte(REPLY_OK); |
| DataSerializer.writeByteArray(keyBytes, dos); |
| } |
| // Now send the server challenge |
| DataSerializer.writeByteArray(challenge, dos); |
| securityLogWriter.fine("HandShake: sent the public key and challenge"); |
| dos.flush(); |
| |
| // Read and decrypt the credentials |
| byte[] encBytes = DataSerializer.readByteArray(dis); |
| KeyAgreement ka = KeyAgreement.getInstance("DH"); |
| ka.init(dhPrivateKey); |
| ka.doPhase(pubKey, true); |
| |
| Cipher decrypt; |
| |
| int keysize = getKeySize(skAlgo); |
| int blocksize = getBlockSize(skAlgo); |
| |
| if (keysize == -1 || blocksize == -1) { |
| SecretKey sKey = ka.generateSecret(skAlgo); |
| decrypt = Cipher.getInstance(skAlgo); |
| decrypt.init(Cipher.DECRYPT_MODE, sKey); |
| } |
| else { |
| String algoStr = getDhAlgoStr(skAlgo); |
| |
| byte[] sKeyBytes = ka.generateSecret(); |
| SecretKeySpec sks = new SecretKeySpec(sKeyBytes, 0, keysize, algoStr); |
| IvParameterSpec ivps = new IvParameterSpec(sKeyBytes, keysize, blocksize); |
| |
| decrypt = Cipher.getInstance(algoStr + "/CBC/PKCS5Padding"); |
| decrypt.init(Cipher.DECRYPT_MODE, sks, ivps); |
| } |
| |
| byte[] credentialBytes = decrypt.doFinal(encBytes); |
| ByteArrayInputStream bis = new ByteArrayInputStream(credentialBytes); |
| DataInputStream dinp = new DataInputStream(bis); |
| credentials = DataSerializer.readProperties(dinp); |
| byte[] challengeRes = DataSerializer.readByteArray(dinp); |
| // Check the challenge string |
| if (!Arrays.equals(challenge, challengeRes)) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_MISMATCH_IN_CHALLENGE_BYTES_MALICIOUS_CLIENT |
| .toLocalizedString()); |
| } |
| dinp.close(); |
| } |
| else { |
| if (sendAuthentication) { |
| // Read and ignore the client challenge |
| DataSerializer.readByteArray(dis); |
| } |
| dos.writeByte(REPLY_AUTH_NOT_REQUIRED); |
| dos.flush(); |
| } |
| }else if (secureMode == SECURITY_MULTIUSER_NOTIFICATIONCHANNEL) |
| { |
| //TODO:hitesh there will be no credential CCP will get credential(Principal) using ServerConnection.. |
| logger.debug("readCredential where multiuser mode creating callback connection"); |
| } |
| } |
| catch (IOException ex) { |
| throw ex; |
| } |
| catch (GemFireSecurityException ex) { |
| throw ex; |
| } |
| catch (Exception ex) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_FAILURE_IN_READING_CREDENTIALS |
| .toLocalizedString(), |
| ex); |
| } |
| return credentials; |
| } |
| |
| public static Principal verifyCredentials(String authenticatorMethod, |
| Properties credentials, Properties securityProperties, InternalLogWriter logWriter, |
| InternalLogWriter securityLogWriter, DistributedMember member) |
| throws AuthenticationRequiredException, AuthenticationFailedException { |
| |
| Authenticator auth = null; |
| try { |
| if (authenticatorMethod == null || authenticatorMethod.length() == 0) { |
| return null; |
| } |
| Method instanceGetter = ClassLoadUtil.methodFromName(authenticatorMethod); |
| auth = (Authenticator)instanceGetter.invoke(null, (Object[])null); |
| } |
| catch (Exception ex) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_FAILED_TO_ACQUIRE_AUTHENTICATOR_OBJECT.toLocalizedString(), ex); |
| } |
| if (auth == null) { |
| throw new AuthenticationFailedException( |
| LocalizedStrings.HandShake_AUTHENTICATOR_INSTANCE_COULD_NOT_BE_OBTAINED.toLocalizedString()); |
| } |
| auth.init(securityProperties, logWriter, securityLogWriter); |
| Principal principal; |
| try { |
| principal = auth.authenticate(credentials, member); |
| } |
| finally { |
| auth.close(); |
| } |
| return principal; |
| } |
| |
| public Principal verifyCredentials() throws AuthenticationRequiredException, |
| AuthenticationFailedException { |
| |
| String methodName = this.system.getProperties().getProperty( |
| DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME); |
| return verifyCredentials(methodName, this.credentials, this.system |
| .getSecurityProperties(), (InternalLogWriter)this.system.getLogWriter(), (InternalLogWriter)this.system |
| .getSecurityLogWriter(), this.id.getDistributedMember()); |
| } |
| |
| public void sendCredentialsForWan(OutputStream out, InputStream in) { |
| |
| try { |
| Properties wanCredentials = getCredentials(this.system |
| .getDistributedMember()); |
| DataOutputStream dos = new DataOutputStream(out); |
| DataInputStream dis = new DataInputStream(in); |
| writeCredentials(dos, dis, wanCredentials, false, this.system.getDistributedMember()); |
| } |
| // The exception while getting the credentials is just logged as severe |
| catch (Exception e) { |
| this.system.getSecurityLogWriter().convertToLogWriterI18n().severe( |
| LocalizedStrings.HandShake_AN_EXCEPTION_WAS_THROWN_WHILE_SENDING_WAN_CREDENTIALS_0, |
| e.getLocalizedMessage()); |
| } |
| } |
| |
| private void checkIfAuthenticWanSite(DataInputStream dis, |
| DataOutputStream dos, DistributedMember member) |
| throws GemFireSecurityException, IOException { |
| |
| if (this.credentials == null) { |
| return; |
| } |
| String authenticator = this.system.getProperties().getProperty( |
| DistributionConfig.SECURITY_CLIENT_AUTHENTICATOR_NAME); |
| Properties peerWanProps = readCredentials(dis, dos, authenticator, |
| this.system); |
| verifyCredentials(authenticator, peerWanProps, this.system |
| .getSecurityProperties(), (InternalLogWriter)this.system.getLogWriter(), (InternalLogWriter)this.system |
| .getSecurityLogWriter(), member); |
| } |
| |
| private static int getKeySize(String skAlgo) { |
| // skAlgo contain both algo and key size info |
| int colIdx = skAlgo.indexOf(':'); |
| String algoStr; |
| int algoKeySize = 0; |
| if (colIdx >= 0) { |
| algoStr = skAlgo.substring(0, colIdx); |
| algoKeySize = Integer.parseInt(skAlgo.substring(colIdx + 1)); |
| } |
| else { |
| algoStr = skAlgo; |
| } |
| int keysize = -1; |
| if (algoStr.equalsIgnoreCase("DESede")) { |
| keysize = 24; |
| } |
| else if (algoStr.equalsIgnoreCase("Blowfish")) { |
| keysize = algoKeySize > 128 ? algoKeySize / 8 : 16; |
| } |
| else if (algoStr.equalsIgnoreCase("AES")) { |
| keysize = (algoKeySize != 192 && algoKeySize != 256) ? 16 |
| : algoKeySize / 8; |
| } |
| return keysize; |
| } |
| |
| private static String getDhAlgoStr(String skAlgo) { |
| int colIdx = skAlgo.indexOf(':'); |
| String algoStr; |
| if (colIdx >= 0) { |
| algoStr = skAlgo.substring(0, colIdx); |
| } |
| else { |
| algoStr = skAlgo; |
| } |
| return algoStr; |
| } |
| |
| private static int getBlockSize(String skAlgo) { |
| int blocksize = -1; |
| String algoStr = getDhAlgoStr(skAlgo); |
| if (algoStr.equalsIgnoreCase("DESede")) { |
| blocksize = 8; |
| } |
| else if (algoStr.equalsIgnoreCase("Blowfish")) { |
| blocksize = 8; |
| } |
| else if (algoStr.equalsIgnoreCase("AES")) { |
| blocksize = 16; |
| } |
| return blocksize; |
| } |
| |
| public Version getVersion() { |
| return this.clientVersion; |
| } |
| |
| public static boolean isDeltaEnabledOnServer() { |
| return deltaEnabledOnServer; |
| } |
| |
| public boolean hasCredentials() { |
| return this.credentials != null; |
| } |
| } |