You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ge...@apache.org on 2006/07/19 00:50:14 UTC
svn commit: r423275 [2/7] - in
/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org:
./ apache/ apache/harmony/ apache/harmony/security/
apache/harmony/security/provider/ apache/harmony/security/provider/jsse/
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHandshakeImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHandshakeImpl.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHandshakeImpl.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHandshakeImpl.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,620 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Boris Kuznetsov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedExceptionAction;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Enumeration;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.interfaces.DHKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.X509ExtendedKeyManager;
+
+/**
+ * Client side handshake protocol implementation.
+ * Handshake protocol operates on top of the Record Protocol.
+ * It is responsible for session negotiating.
+ *
+ * The implementation proceses inbound server handshake messages,
+ * creates and sends respond messages. Outbound messages are supplied
+ * to Record Protocol. Detected errors are reported to the Alert protocol.
+ *
+ * @see TLS 1.0 spec., 7. The TLS Handshake Protocol
+ * (http://www.ietf.org/rfc/rfc2246.txt)
+ *
+ */
+public class ClientHandshakeImpl extends HandshakeProtocol {
+
+ /**
+ * Creates Client Handshake Implementation
+ *
+ * @param owner
+ */
+ ClientHandshakeImpl(Object owner) {
+ super(owner);
+ }
+
+ /**
+ * Starts handshake
+ *
+ */
+ public void start() {
+ if (session == null) { // initial handshake
+ session = findSessionToResume();
+ } else { // start session renegotiation
+ if (clientHello != null && this.status != FINISHED) {
+ // current negotiation has not completed
+ return; // ignore
+ }
+ if (!session.isValid()) {
+ session = null;
+ }
+ }
+ if (session != null) {
+ isResuming = true;
+ } else if (parameters.getEnableSessionCreation()){
+ isResuming = false;
+ session = new SSLSessionImpl(parameters.getSecureRandom());
+ session.protocol = ProtocolVersion.getLatestVersion(parameters
+ .getEnabledProtocols());
+ recordProtocol.setVersion(session.protocol.version);
+ } else {
+ fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "SSL Session may not be created ");
+ }
+ startSession();
+ }
+
+ /**
+ * Starts renegotiation on a new session
+ *
+ */
+ private void renegotiateNewSession() {
+ if (parameters.getEnableSessionCreation()){
+ isResuming = false;
+ session = new SSLSessionImpl(parameters.getSecureRandom());
+ session.protocol = ProtocolVersion.getLatestVersion(parameters
+ .getEnabledProtocols());
+ recordProtocol.setVersion(session.protocol.version);
+ startSession();
+ } else {
+ status = NOT_HANDSHAKING;
+ sendWarningAlert(AlertProtocol.NO_RENEGOTIATION);
+ }
+ }
+
+ /*
+ * Starts/resumes session
+ */
+ private void startSession() {
+ CipherSuite[] cipher_suites;
+ if (isResuming) {
+ cipher_suites = new CipherSuite[] { session.cipherSuite };
+ } else {
+ cipher_suites = parameters.enabledCipherSuites;
+ }
+ clientHello = new ClientHello(parameters.getSecureRandom(),
+ session.protocol.version, session.id, cipher_suites);
+ session.clientRandom = clientHello.random;
+ send(clientHello);
+ status = NEED_UNWRAP;
+ }
+
+ /**
+ * Proceses inbound handshake messages
+ * @param bytes
+ */
+ public void unwrap(byte[] bytes) {
+ if (this.delegatedTaskErr != null) {
+ Exception e = this.delegatedTaskErr;
+ this.delegatedTaskErr = null;
+ this.fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "Error in delegated task", e);
+ }
+ int handshakeType;
+ io_stream.append(bytes);
+ while (io_stream.available() > 0) {
+ io_stream.mark();
+ int length;
+ try {
+ handshakeType = io_stream.read();
+ length = io_stream.readUint24();
+ if (io_stream.available() < length) {
+ io_stream.reset();
+ return;
+ }
+ switch (handshakeType) {
+ case 0: // HELLO_REQUEST
+ // we don't need to take this message into account
+ // during FINISH message verification, so remove it
+ io_stream.removeFromMarkedPosition();
+ if (clientHello != null
+ && (clientFinished == null || serverFinished == null)) {
+ //currently negotiating - ignore
+ break;
+ }
+ // renegotiate
+ if (session.isValid()) {
+ session = (SSLSessionImpl) session.clone();
+ isResuming = true;
+ startSession();
+ } else {
+ // if SSLSession is invalidated (e.g. timeout limit is
+ // exceeded) connection can't resume the session.
+ renegotiateNewSession();
+ }
+ break;
+ case 2: // SERVER_HELLO
+ if (clientHello == null || serverHello != null) {
+ unexpectedMessage();
+ return;
+ }
+ serverHello = new ServerHello(io_stream, length);
+
+ //check protocol version
+ ProtocolVersion servProt = ProtocolVersion
+ .getByVersion(serverHello.server_version);
+ String[] enabled = parameters.getEnabledProtocols();
+ find: {
+ for (int i = 0; i < enabled.length; i++) {
+ if (servProt.equals(ProtocolVersion
+ .getByName(enabled[i]))) {
+ break find;
+ }
+ }
+ fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
+ "Bad server hello protocol version");
+ }
+
+ // check compression method
+ if (serverHello.compression_method != 0) {
+ fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
+ "Bad server hello compression method");
+ }
+
+ //check cipher_suite
+ CipherSuite[] enabledSuites = parameters.enabledCipherSuites;
+ find: {
+ for (int i = 0; i < enabledSuites.length; i++) {
+ if (serverHello.cipher_suite
+ .equals(enabledSuites[i])) {
+ break find;
+ }
+ }
+ fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
+ "Bad server hello cipher suite");
+ }
+
+ if (isResuming) {
+ if (serverHello.session_id.length == 0) {
+ // server is not willing to establish the new connection
+ // using specified session
+ isResuming = false;
+ } else if (!Arrays.equals(serverHello.session_id, clientHello.session_id)) {
+ isResuming = false;
+ } else if (!session.protocol.equals(servProt)) {
+ fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
+ "Bad server hello protocol version");
+ } else if (!session.cipherSuite
+ .equals(serverHello.cipher_suite)) {
+ fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
+ "Bad server hello cipher suite");
+ }
+ if (serverHello.server_version[1] == 1) {
+ computerReferenceVerifyDataTLS("server finished");
+ } else {
+ computerReferenceVerifyDataSSLv3(SSLv3Constants.server);
+ }
+ }
+ session.protocol = servProt;
+ recordProtocol.setVersion(session.protocol.version);
+ session.cipherSuite = serverHello.cipher_suite;
+ session.id = (byte[]) serverHello.session_id.clone();
+ session.serverRandom = serverHello.random;
+ break;
+ case 11: // CERTIFICATE
+ if (serverHello == null || serverKeyExchange != null
+ || serverCert != null || isResuming) {
+ unexpectedMessage();
+ return;
+ }
+ serverCert = new CertificateMessage(io_stream, length);
+ break;
+ case 12: // SERVER_KEY_EXCHANGE
+ if (serverHello == null || serverKeyExchange != null
+ || isResuming) {
+ unexpectedMessage();
+ return;
+ }
+ serverKeyExchange = new ServerKeyExchange(io_stream,
+ length, session.cipherSuite.keyExchange);
+ break;
+ case 13: // CERTIFICATE_REQUEST
+ if (serverCert == null || certificateRequest != null
+ || session.cipherSuite.isAnonymous() || isResuming) {
+ unexpectedMessage();
+ return;
+ }
+ certificateRequest = new CertificateRequest(io_stream,
+ length);
+ break;
+ case 14: // SERVER_HELLO_DONE
+ if (serverHello == null || serverHelloDone != null
+ || isResuming) {
+ unexpectedMessage();
+ return;
+ }
+ serverHelloDone = new ServerHelloDone(io_stream, length);
+ if (this.nonBlocking) {
+ delegatedTasks.add(new DelegatedTask(
+ new PrivilegedExceptionAction(){
+ public Object run() throws Exception {
+ processServerHelloDone();
+ return null;
+ }
+ },
+ this,
+ AccessController.getContext()));
+ return;
+ }
+ processServerHelloDone();
+ break;
+ case 20: // FINISHED
+ if (!changeCipherSpecReceived) {
+ unexpectedMessage();
+ return;
+ }
+ serverFinished = new Finished(io_stream, length);
+ verifyFinished(serverFinished.getData());
+ session.lastAccessedTime = System.currentTimeMillis();
+ parameters.getClientSessionContext().putSession(session);
+ if (isResuming) {
+ sendChangeCipherSpec();
+ } else {
+ session.lastAccessedTime = System.currentTimeMillis();
+ status = FINISHED;
+ }
+ // XXX there is no cleanup work
+ break;
+ default:
+ unexpectedMessage();
+ return;
+ }
+ } catch (IOException e) {
+ // io stream dosn't contain complete handshake message
+ io_stream.reset();
+ return;
+ }
+ }
+
+ }
+
+ /**
+ * Processes SSLv2 Hello message.
+ * SSLv2 client hello message message is an unexpected message
+ * for client side of handshake protocol.
+ * @ see TLS 1.0 spec., E.1. Version 2 client hello
+ * @param bytes
+ */
+ public void unwrapSSLv2(byte[] bytes) {
+ unexpectedMessage();
+ }
+
+ /**
+ * Creates and sends Finished message
+ */
+ protected void makeFinished() {
+ byte[] verify_data;
+ if (serverHello.server_version[1] == 1) {
+ verify_data = new byte[12];
+ computerVerifyDataTLS("client finished", verify_data);
+ } else {
+ verify_data = new byte[36];
+ computerVerifyDataSSLv3(SSLv3Constants.client, verify_data);
+ }
+ clientFinished = new Finished(verify_data);
+ send(clientFinished);
+ if (isResuming) {
+ session.lastAccessedTime = System.currentTimeMillis();
+ status = FINISHED;
+ } else {
+ if (serverHello.server_version[1] == 1) {
+ computerReferenceVerifyDataTLS("server finished");
+ } else {
+ computerReferenceVerifyDataSSLv3(SSLv3Constants.server);
+ }
+ status = NEED_UNWRAP;
+ }
+ }
+
+ /**
+ * Processes ServerHelloDone: makes verification of the server messages; sends
+ * client messages, computers masterSecret, sends ChangeCipherSpec
+ */
+ void processServerHelloDone() {
+ if (serverCert != null) {
+ if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon
+ || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon_EXPORT) {
+ unexpectedMessage();
+ return;
+ }
+ verifyServerCert();
+ } else {
+ if (session.cipherSuite.keyExchange != CipherSuite.KeyExchange_DH_anon
+ && session.cipherSuite.keyExchange != CipherSuite.KeyExchange_DH_anon_EXPORT) {
+ unexpectedMessage();
+ return;
+ }
+ }
+
+ // Client certificate
+ if (certificateRequest != null) {
+ X509Certificate[] certs = null;
+ String clientAlias = ((X509ExtendedKeyManager) parameters
+ .getKeyManager()).chooseClientAlias(certificateRequest
+ .getTypesAsString(),
+ certificateRequest.certificate_authorities, null);
+ if (clientAlias != null) {
+ certs = ((X509ExtendedKeyManager) parameters.getKeyManager())
+ .getCertificateChain((clientAlias));
+ }
+ session.localCertificates = certs;
+ clientCert = new CertificateMessage(certs);
+ send(clientCert);
+ }
+ // Client key exchange
+ if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA
+ || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
+ // RSA encrypted premaster secret message
+ Cipher c;
+ try {
+ c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ if (serverKeyExchange != null) {
+ c.init(Cipher.ENCRYPT_MODE, serverKeyExchange
+ .getRSAPublicKey());
+ } else {
+ c.init(Cipher.ENCRYPT_MODE, serverCert.certs[0]);
+ }
+ } catch (Exception e) {
+ fatalAlert(AlertProtocol.INTERNAL_ERROR,
+ "Unexpected exception", e);
+ return;
+ }
+ preMasterSecret = new byte[48];
+ parameters.getSecureRandom().nextBytes(preMasterSecret);
+ System.arraycopy(clientHello.client_version, 0, preMasterSecret, 0,
+ 2);
+ try {
+ clientKeyExchange = new ClientKeyExchange(c
+ .doFinal(preMasterSecret),
+ serverHello.server_version[1] == 1);
+ } catch (Exception e) {
+ fatalAlert(AlertProtocol.INTERNAL_ERROR,
+ "Unexpected exception", e);
+ return;
+ }
+ } else {
+ PublicKey serverPublic;
+ KeyAgreement agreement = null;
+ DHParameterSpec spec;
+ try {
+ KeyFactory kf = null;
+ try {
+ kf = KeyFactory.getInstance("DH");
+ } catch (NoSuchAlgorithmException e) {
+ kf = KeyFactory.getInstance("DiffieHellman");
+ }
+
+ try {
+ agreement = KeyAgreement.getInstance("DH");
+ } catch (NoSuchAlgorithmException ee) {
+ agreement = KeyAgreement.getInstance("DiffieHellman");
+ }
+
+ KeyPairGenerator kpg = null;
+ try {
+ kpg = KeyPairGenerator.getInstance("DH");
+ } catch (NoSuchAlgorithmException e) {
+ kpg = KeyPairGenerator.getInstance("DiffieHellman");
+ }
+ if (serverKeyExchange != null) {
+ serverPublic = kf.generatePublic(new DHPublicKeySpec(
+ serverKeyExchange.par3, serverKeyExchange.par1,
+ serverKeyExchange.par2));
+ spec = new DHParameterSpec(serverKeyExchange.par1,
+ serverKeyExchange.par2);
+ } else {
+ serverPublic = serverCert.certs[0].getPublicKey();
+ spec = ((DHPublicKey) serverPublic).getParams();
+ }
+ kpg.initialize(spec);
+
+ KeyPair kp = kpg.generateKeyPair();
+ Key key = kp.getPublic();
+ if (clientCert != null
+ && serverCert != null
+ && (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA
+ || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS)) {
+ PublicKey client_pk = clientCert.certs[0].getPublicKey();
+ PublicKey server_pk = serverCert.certs[0].getPublicKey();
+ if (client_pk instanceof DHKey
+ && server_pk instanceof DHKey) {
+ if (((DHKey) client_pk).getParams().getG().equals(
+ ((DHKey) server_pk).getParams().getG())
+ && ((DHKey) client_pk).getParams().getP()
+ .equals(((DHKey) server_pk).getParams().getG())) {
+ // client cert message DH public key parameters
+ // matched those specified by the
+ // server in its certificate,
+ clientKeyExchange = new ClientKeyExchange(); // empty
+ }
+ }
+ } else {
+ clientKeyExchange = new ClientKeyExchange(
+ ((DHPublicKey) key).getY());
+ }
+ key = kp.getPrivate();
+ agreement.init(key);
+ agreement.doPhase(serverPublic, true);
+ preMasterSecret = agreement.generateSecret();
+ } catch (Exception e) {
+ fatalAlert(AlertProtocol.INTERNAL_ERROR,
+ "Unexpected exception", e);
+ return;
+ }
+ }
+ if (clientKeyExchange != null) {
+ send(clientKeyExchange);
+ }
+
+ computerMasterSecret();
+
+ if (clientCert != null) {
+ boolean[] keyUsage = clientCert.certs[0].getKeyUsage();
+ if (keyUsage != null && keyUsage[0]) {
+ // Certificate verify
+ DigitalSignature ds = new DigitalSignature(
+ session.cipherSuite.keyExchange);
+ if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT
+ || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA
+ || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
+ ds.setMD5(io_stream.getDigestMD5());
+ ds.setSHA(io_stream.getDigestSHA());
+ } else if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS
+ || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
+ ds.setSHA(io_stream.getDigestSHA());
+ // The Signature should be empty in case of anonimous signature algorithm:
+ // } else if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon ||
+ // session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon_EXPORT) {
+ }
+ certificateVerify = new CertificateVerify(ds.sign());
+ send(certificateVerify);
+ }
+ }
+
+ sendChangeCipherSpec();
+ }
+
+ /*
+ * Verifies certificate path
+ */
+ private void verifyServerCert() {
+ String authType = null;
+ switch (session.cipherSuite.keyExchange) {
+ case 1: // KeyExchange_RSA
+ authType = "RSA";
+ break;
+ case 2: // KeyExchange_RSA_EXPORT
+ if (serverKeyExchange != null ) {
+ // ephemeral RSA key is used
+ authType = "RSA_EXPORT";
+ } else {
+ authType = "RSA";
+ }
+ break;
+ case 3: // KeyExchange_DHE_DSS
+ case 4: // KeyExchange_DHE_DSS_EXPORT
+ authType = "DHE_DSS";
+ break;
+ case 5: // KeyExchange_DHE_RSA
+ case 6: // KeyExchange_DHE_RSA_EXPORT
+ authType = "DHE_RSA";
+ break;
+ case 7: // KeyExchange_DH_DSS
+ case 11: // KeyExchange_DH_DSS_EXPORT
+ authType = "DH_DSS";
+ break;
+ case 8: // KeyExchange_DH_RSA
+ case 12: // KeyExchange_DH_RSA_EXPORT
+ authType = "DH_RSA";
+ break;
+ case 9: // KeyExchange_DH_anon
+ case 10: // KeyExchange_DH_anon_EXPORT
+ return;
+ }
+ try {
+ parameters.getTrustManager().checkServerTrusted(serverCert.certs,
+ authType);
+ } catch (CertificateException e) {
+ fatalAlert(AlertProtocol.BAD_CERTIFICATE, "Not trusted server certificate", e);
+ return;
+ }
+ session.peerCertificates = serverCert.certs;
+ }
+
+ /**
+ * Proceses ChangeCipherSpec message
+ */
+ public void receiveChangeCipherSpec() {
+ if (isResuming) {
+ if (serverHello == null) {
+ unexpectedMessage();
+ }
+ } else if (clientFinished == null) {
+ unexpectedMessage();
+ }
+ changeCipherSpecReceived = true;
+ }
+
+ // Find session to resume in client session context
+ private SSLSessionImpl findSessionToResume() {
+ String host;
+ int port;
+ if (engineOwner != null) {
+ host = engineOwner.getPeerHost();
+ port = engineOwner.getPeerPort();
+ } else {
+ host = socketOwner.getInetAddress().getHostName();
+ port = socketOwner.getPort();
+ }
+ if (host == null || port == -1) {
+ return null; // starts new session
+ }
+
+ byte[] id;
+ SSLSession ses;
+ SSLSessionContext context = parameters.getClientSessionContext();
+ for (Enumeration en = context.getIds(); en.hasMoreElements();) {
+ id = (byte[])en.nextElement();
+ ses = context.getSession(id);
+ if (host.equals(ses.getPeerHost()) && port == ses.getPeerPort()) {
+ return (SSLSessionImpl)((SSLSessionImpl)ses).clone(); // resume
+ }
+ }
+ return null; // starts new session
+ }
+
+}
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHello.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHello.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHello.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientHello.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.io.IOException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+/**
+ *
+ * Represents Client Hello message
+ * @see TLS 1.0 spec., 7.4.1.2. Client hello
+ * (http://www.ietf.org/rfc/rfc2246.txt)
+ *
+ */
+public class ClientHello extends Message {
+
+ /**
+ * Client version
+ */
+ final byte[] client_version;
+
+ /**
+ * Random bytes
+ */
+ final byte[] random = new byte[32];
+
+ /**
+ * Session id
+ */
+ final byte[] session_id;
+
+ /**
+ * Cipher suites supported by the client
+ */
+ final CipherSuite[] cipher_suites;
+
+ /**
+ * Compression methods supported by the client
+ */
+ final byte[] compression_methods;
+
+ /**
+ * Creates outbound message
+ * @param sr
+ * @param version
+ * @param ses_id
+ * @param cipher_suite
+ */
+ public ClientHello(SecureRandom sr, byte[] version, byte[] ses_id,
+ CipherSuite[] cipher_suite) {
+ client_version = version;
+ long gmt_unix_time = System.currentTimeMillis()/1000;
+ sr.nextBytes(random);
+ random[0] = (byte) (gmt_unix_time & 0xFF000000 >>> 24);
+ random[1] = (byte) (gmt_unix_time & 0xFF0000 >>> 16);
+ random[2] = (byte) (gmt_unix_time & 0xFF00 >>> 8);
+ random[3] = (byte) (gmt_unix_time & 0xFF);
+ session_id = ses_id;
+ this.cipher_suites = cipher_suite;
+ compression_methods = new byte[] { 0 }; // CompressionMethod.null
+ length = 38 + session_id.length + (this.cipher_suites.length << 1)
+ + compression_methods.length;
+ }
+
+ /**
+ * Creates inbound message
+ * @param in
+ * @param length
+ * @throws IOException
+ */
+ public ClientHello(HandshakeIODataStream in, int length) throws IOException {
+ client_version = new byte[2];
+ client_version[0] = (byte) in.readUint8();
+ client_version[1] = (byte) in.readUint8();
+ in.read(random, 0, 32);
+ int size = in.read();
+ session_id = new byte[size];
+ in.read(session_id, 0, size);
+ int l = in.readUint16();
+ if ((l & 0x01) == 0x01) { // cipher suites length must be an even number
+ fatalAlert(AlertProtocol.DECODE_ERROR,
+ "DECODE ERROR: incorrect ClientHello");
+ }
+ size = l >> 1;
+ cipher_suites = new CipherSuite[size];
+ for (int i = 0; i < size; i++) {
+ byte b0 = (byte) in.read();
+ byte b1 = (byte) in.read();
+ cipher_suites[i] = CipherSuite.getByCode(b0, b1);
+ }
+ size = in.read();
+ compression_methods = new byte[size];
+ in.read(compression_methods, 0, size);
+ this.length = 38 + session_id.length + (cipher_suites.length << 1)
+ + compression_methods.length;
+ if (this.length > length) {
+ fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect ClientHello");
+ }
+ // for forward compatibility, extra data is permitted;
+ // must be ignored
+ if (this.length < length) {
+ in.skip(length - this.length);
+ this.length = length;
+ }
+ }
+ /**
+ * Parse V2ClientHello
+ * @param in
+ * @throws IOException
+ */
+ public ClientHello(HandshakeIODataStream in) throws IOException {
+ if (in.readUint8() != 1) {
+ fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect V2ClientHello");
+ }
+ client_version = new byte[2];
+ client_version[0] = (byte) in.readUint8();
+ client_version[1] = (byte) in.readUint8();
+ int cipher_spec_length = in.readUint16();
+ if (in.readUint16() != 0) { // session_id_length
+ // as client already knows the protocol known to a server it should
+ // initiate the connection in that native protocol
+ fatalAlert(AlertProtocol.DECODE_ERROR,
+ "DECODE ERROR: incorrect V2ClientHello, cannot be used for resuming");
+ }
+ int challenge_length = in.readUint16();
+ if (challenge_length < 16) {
+ fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect V2ClientHello, short challenge data");
+ }
+ session_id = new byte[0];
+ cipher_suites = new CipherSuite[cipher_spec_length/3];
+ for (int i = 0; i < cipher_suites.length; i++) {
+ byte b0 = (byte) in.read();
+ byte b1 = (byte) in.read();
+ byte b2 = (byte) in.read();
+ cipher_suites[i] = CipherSuite.getByCode(b0, b1, b2);
+ }
+ compression_methods = new byte[] { 0 }; // CompressionMethod.null
+
+ if (challenge_length < 32) {
+ Arrays.fill(random, 0, 32 - challenge_length, (byte)0);
+ System.arraycopy(in.read(challenge_length), 0, random, 32 - challenge_length, challenge_length);
+ } else if (challenge_length == 32) {
+ System.arraycopy(in.read(32), 0, random, 0, 32);
+ } else {
+ System.arraycopy(in.read(challenge_length), challenge_length - 32, random, 0, 32);
+ }
+ if (in.available() > 0) {
+ fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect V2ClientHello, extra data");
+ }
+ this.length = 38 + session_id.length + (cipher_suites.length << 1)
+ + compression_methods.length;
+ }
+
+ /**
+ * Sends message
+ * @param out
+ */
+ public void send(HandshakeIODataStream out) {
+ out.write(client_version);
+ out.write(random);
+ out.writeUint8(session_id.length);
+ out.write(session_id);
+ int size = cipher_suites.length << 1;
+ out.writeUint16(size);
+ for (int i = 0; i < cipher_suites.length; i++) {
+ out.write(cipher_suites[i].toBytes());
+ }
+ out.writeUint8(compression_methods.length);
+ for (int i = 0; i < compression_methods.length; i++) {
+ out.write(compression_methods[i]);
+ }
+ }
+
+ /**
+ * Returns client random
+ * @return client random
+ */
+ public byte[] getRandom() {
+ return random;
+ }
+
+ /**
+ * Returns message type
+ * @return
+ */
+ public int getType() {
+ return Handshake.CLIENT_HELLO;
+ }
+}
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientKeyExchange.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientKeyExchange.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientKeyExchange.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ClientKeyExchange.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+* @author Boris Kuznetsov
+* @version $Revision$
+*/
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ *
+ * Represents client key exchange message
+ * @see TLS 1.0 spec., 7.4.7. Client key exchange message
+ * (http://www.ietf.org/rfc/rfc2246.txt)
+ *
+ */
+public class ClientKeyExchange extends Message {
+
+ /**
+ * Exchange keys
+ */
+ final byte[] exchange_keys;
+
+ /**
+ * Equals true if TLS1.0 protocol is used
+ */
+ boolean isTLS;
+
+ /**
+ * Equals true if key exchange algorithm is RSA
+ */
+ final boolean isRSA;
+
+ /**
+ * Creates outbound message
+ * @param encrypted_pre_master_secret
+ * @param isTLS
+ */
+ public ClientKeyExchange(byte[] encrypted_pre_master_secret, boolean isTLS) {
+ this.exchange_keys = encrypted_pre_master_secret;
+ length = this.exchange_keys.length;
+ if (isTLS) {
+ length += 2;
+ }
+ this.isTLS = isTLS;
+ isRSA = true;
+ }
+
+ /**
+ * Creates outbound message
+ * @param dh_Yc
+ */
+ public ClientKeyExchange(BigInteger dh_Yc) {
+ byte[] bb = dh_Yc.toByteArray();
+ if (bb[0] == 0) {
+ exchange_keys = new byte[bb.length-1];
+ System.arraycopy(bb, 1, exchange_keys, 0, exchange_keys.length);
+ } else {
+ exchange_keys = bb;
+ }
+ length = exchange_keys.length +2;
+ isRSA = false;
+ }
+
+ /**
+ * Creates empty message
+ *
+ */
+ public ClientKeyExchange() {
+ exchange_keys = new byte[0];
+ length = 0;
+ isRSA = false;
+ }
+
+ /**
+ * Creates inbound message
+ * @param length
+ * @param isTLS
+ * @param isRSA
+ * @throws IOException
+ */
+ public ClientKeyExchange(HandshakeIODataStream in, int length, boolean isTLS, boolean isRSA)
+ throws IOException {
+ this.isTLS = isTLS;
+ this.isRSA = isRSA;
+ if (length == 0) {
+ this.length = 0;
+ exchange_keys = new byte[0];
+ } else {
+ int size;
+ if (isRSA && !isTLS) {// SSL3.0 RSA
+ size = length;
+ this.length = size;
+ } else { // DH or TLSv1 RSA
+ size = in.readUint16();
+ this.length = 2 + size;
+ }
+ exchange_keys = new byte[size];
+ in.read(exchange_keys, 0, size);
+ if (this.length != length) {
+ fatalAlert(AlertProtocol.DECODE_ERROR, "DECODE ERROR: incorrect ClientKeyExchange");
+ }
+ }
+ }
+
+ /**
+ * Sends message
+ * @param out
+ */
+ public void send(HandshakeIODataStream out) {
+ if (exchange_keys.length != 0) {
+ if (!isRSA || isTLS) {// DH or TLSv1 RSA
+ out.writeUint16(exchange_keys.length);
+ }
+ out.write(exchange_keys);
+ }
+ }
+
+ /**
+ * Returns message type
+ * @return
+ */
+ public int getType() {
+ return Handshake.CLIENT_KEY_EXCHANGE;
+ }
+
+ /**
+ * Returns true if the message is empty (in case of implicit DH Yc)
+ * @return
+ */
+ public boolean isEmpty() {
+ return (exchange_keys.length == 0);
+ }
+}
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionState.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionState.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionState.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionState.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import javax.crypto.Cipher;
+
+/**
+ * This abstract class is a base for Record Protocol operating environmet
+ * of different SSL protocol versions.
+ */
+public abstract class ConnectionState {
+
+ /**
+ * The cipher used for encode operations
+ */
+ protected Cipher encCipher;
+
+ /**
+ * The cipher used for decode operations
+ */
+ protected Cipher decCipher;
+
+ /**
+ * The cipher type
+ */
+ protected boolean is_block_cipher;
+
+ /**
+ * The size of MAC used under this connection state
+ */
+ protected int hash_size;
+
+ /**
+ * Write sequence number which is incremented after each
+ * encrypt call
+ */
+ protected final byte[] write_seq_num = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ /**
+ * Read sequence number which is incremented after each
+ * decrypt call
+ */
+ protected final byte[] read_seq_num = {0, 0, 0, 0, 0, 0, 0, 0};
+
+ protected Logger.Stream logger = Logger.getStream("conn_state");
+
+ /**
+ * Returns the minimal possible size of the
+ * Generic[Stream|Generic]Cipher structure under this
+ * connection state.
+ */
+ protected int getMinFragmentSize() {
+ // block ciphers return value with padding included
+ return encCipher.getOutputSize(1+hash_size); // 1 byte for data
+ }
+
+ /**
+ * Returns the size of the Generic[Stream|Generic]Cipher structure
+ * corresponding to the content data of specified size.
+ */
+ protected int getFragmentSize(int content_size) {
+ return encCipher.getOutputSize(content_size+hash_size);
+ }
+
+ /**
+ * Returns the minimal upper bound of the content size enclosed
+ * into the Generic[Stream|Generic]Cipher structure of specified size.
+ * For stream ciphers the returned value will be exact value.
+ */
+ protected int getContentSize(int generic_cipher_size) {
+ //it does not take the padding of block ciphered structures
+ //into account (so returned value can be greater than actual)
+ return decCipher.getOutputSize(generic_cipher_size)-hash_size;
+ }
+
+ /**
+ * Creates the GenericStreamCipher or GenericBlockCipher
+ * data structure for specified data of specified type.
+ * @param type - the ContentType of the provided data
+ * @param fragment - the byte array containing the
+ * data to be encrypted under the current connection state.
+ */
+ protected byte[] encrypt(byte type, byte[] fragment) {
+ return encrypt(type, fragment, 0, fragment.length);
+ }
+
+ /**
+ * Creates the GenericStreamCipher or GenericBlockCipher
+ * data structure for specified data of specified type.
+ * @param type - the ContentType of the provided data
+ * @param fragment - the byte array containing the
+ * data to be encrypted under the current connection state.
+ * @param offset - the offset from which the data begins with.
+ * @param len - the length of the data.
+ */
+ protected abstract byte[] encrypt
+ (byte type, byte[] fragment, int offset, int len);
+
+ /**
+ * Retrieves the fragment of the Plaintext structure of
+ * the specified type from the provided data.
+ * @param type - the ContentType of the data to be decrypted.
+ * @param fragment - the byte array containing the
+ * data to be encrypted under the current connection state.
+ */
+ protected byte[] decrypt(byte type, byte[] fragment) {
+ return decrypt(type, fragment, 0, fragment.length);
+ }
+
+ /**
+ * Retrieves the fragment of the Plaintext structure of
+ * the specified type from the provided data.
+ * @param type - the ContentType of the data to be decrypted.
+ * @param fragment - the byte array containing the
+ * data to be encrypted under the current connection state.
+ * @param offset - the offset from which the data begins with.
+ * @param len - the length of the data.
+ */
+ protected abstract byte[] decrypt
+ (byte type, byte[] fragment, int offset, int len);
+
+ /**
+ * Increments the sequence number.
+ */
+ protected static void incSequenceNumber(byte[] seq_num) {
+ int octet = 7;
+ while (octet >= 0) {
+ seq_num[octet] ++;
+ if (seq_num[octet] == 0) {
+ // characteristic overflow, so
+ // carrying a number in adding
+ octet --;
+ } else {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Shutdownes the protocol. It will be impossiblke to use the instance
+ * after the calling of this method.
+ */
+ protected void shutdown() {
+ encCipher = null;
+ decCipher = null;
+ for (int i=0; i<write_seq_num.length; i++) {
+ write_seq_num[i] = 0;
+ read_seq_num[i] = 0;
+ }
+ }
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateSSLv3.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateSSLv3.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateSSLv3.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateSSLv3.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLProtocolException;
+
+/**
+ * This class incapsulates the operating environment of the SSL v3
+ * (http://wp.netscape.com/eng/ssl3) Record Protocol and provides
+ * relating encryption/decryption functionality.
+ * The work functionality is based on the security
+ * parameters negotiated during the handshake.
+ */
+public class ConnectionStateSSLv3 extends ConnectionState {
+
+ // digest to create and check the message integrity info
+ private final MessageDigest messageDigest;
+ private final byte[] mac_write_secret;
+ private final byte[] mac_read_secret;
+
+ // paddings
+ private final byte[] pad_1;
+ private final byte[] pad_2;
+ // array will hold the part of the MAC material:
+ // length of 3 == 1(SSLCompressed.type) + 2(SSLCompressed.length)
+ // (more on SSLv3 MAC computation and payload protection see
+ // SSL v3 specification, p. 5.2.3)
+ private final byte[] mac_material_part = new byte[3];
+
+ /**
+ * Creates the instance of SSL v3 Connection State. All of the
+ * security parameters are provided by session object.
+ * @param session: the sessin object which incapsulates
+ * all of the security parameters established by handshake protocol.
+ * The key calculation for the state is done according
+ * to the SSL v3 Protocol specification.
+ * (http://www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt)
+ */
+ protected ConnectionStateSSLv3(SSLSessionImpl session) {
+ try {
+ CipherSuite cipherSuite = session.cipherSuite;
+
+ boolean is_exportabe = cipherSuite.isExportable();
+ hash_size = cipherSuite.getMACLength();
+ int key_size = (is_exportabe)
+ ? cipherSuite.keyMaterial
+ : cipherSuite.expandedKeyMaterial;
+ int iv_size = cipherSuite.getBlockSize();
+
+ String algName = cipherSuite.getBulkEncryptionAlgorithm();
+ String hashName = cipherSuite.getHashName();
+ if (logger != null) {
+ logger.println("ConnectionStateSSLv3.create:");
+ logger.println(" cipher suite name: "
+ + session.getCipherSuite());
+ logger.println(" encryption alg name: " + algName);
+ logger.println(" hash alg name: " + hashName);
+ logger.println(" hash size: " + hash_size);
+ logger.println(" block size: " + iv_size);
+ logger.println(" IV size (== block size):" + iv_size);
+ logger.println(" key size: " + key_size);
+ }
+
+ byte[] clientRandom = session.clientRandom;
+ byte[] serverRandom = session.serverRandom;
+ // so we need PRF value of size of
+ // 2*hash_size + 2*key_size + 2*iv_size
+ byte[] key_block = new byte[2*hash_size + 2*key_size + 2*iv_size];
+ byte[] seed = new byte[clientRandom.length + serverRandom.length];
+ System.arraycopy(serverRandom, 0, seed, 0, serverRandom.length);
+ System.arraycopy(clientRandom, 0, seed, serverRandom.length,
+ clientRandom.length);
+
+ PRF.computePRF_SSLv3(key_block, session.master_secret, seed);
+
+ byte[] client_mac_secret = new byte[hash_size];
+ byte[] server_mac_secret = new byte[hash_size];
+ byte[] client_key = new byte[key_size];
+ byte[] server_key = new byte[key_size];
+
+ boolean is_client = !session.isServer;
+
+ is_block_cipher = (iv_size > 0);
+
+ System.arraycopy(key_block, 0, client_mac_secret, 0, hash_size);
+ System.arraycopy(key_block, hash_size,
+ server_mac_secret, 0, hash_size);
+ System.arraycopy(key_block, 2*hash_size, client_key, 0, key_size);
+ System.arraycopy(key_block, 2*hash_size+key_size,
+ server_key, 0, key_size);
+
+ IvParameterSpec clientIV = null;
+ IvParameterSpec serverIV = null;
+
+ if (is_exportabe) {
+ if (logger != null) {
+ logger.println("ConnectionStateSSLv3: is_exportable");
+ }
+
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(client_key);
+ md5.update(clientRandom);
+ md5.update(serverRandom);
+ client_key = md5.digest();
+
+ md5.update(server_key);
+ md5.update(serverRandom);
+ md5.update(clientRandom);
+ server_key = md5.digest();
+
+ key_size = cipherSuite.expandedKeyMaterial;
+
+ if (is_block_cipher) {
+ md5.update(clientRandom);
+ md5.update(serverRandom);
+ clientIV = new IvParameterSpec(md5.digest(), 0, iv_size);
+ md5.update(serverRandom);
+ md5.update(clientRandom);
+ serverIV = new IvParameterSpec(md5.digest(), 0, iv_size);
+ }
+ } else if (is_block_cipher) {
+ clientIV = new IvParameterSpec(key_block,
+ 2*hash_size+2*key_size, iv_size);
+ serverIV = new IvParameterSpec(key_block,
+ 2*hash_size+2*key_size+iv_size, iv_size);
+ }
+
+ if (logger != null) {
+ logger.println("is exportable: "+is_exportabe);
+ logger.println("master_secret");
+ logger.print(session.master_secret);
+ logger.println("client_random");
+ logger.print(clientRandom);
+ logger.println("server_random");
+ logger.print(serverRandom);
+ //logger.println("key_block");
+ //logger.print(key_block);
+ logger.println("client_mac_secret");
+ logger.print(client_mac_secret);
+ logger.println("server_mac_secret");
+ logger.print(server_mac_secret);
+ logger.println("client_key");
+ logger.print(client_key, 0, key_size);
+ logger.println("server_key");
+ logger.print(server_key, 0, key_size);
+ if (clientIV != null) {
+ logger.println("client_iv");
+ logger.print(clientIV.getIV());
+ logger.println("server_iv");
+ logger.print(serverIV.getIV());
+ } else {
+ logger.println("no IV.");
+ }
+ }
+ encCipher = Cipher.getInstance(algName);
+ decCipher = Cipher.getInstance(algName);
+ messageDigest = MessageDigest.getInstance(hashName);
+ if (is_client) { // client side
+ encCipher.init(Cipher.ENCRYPT_MODE,
+ new SecretKeySpec(client_key, 0, key_size, algName),
+ clientIV);
+ decCipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(server_key, 0, key_size, algName),
+ serverIV);
+ mac_write_secret = client_mac_secret;
+ mac_read_secret = server_mac_secret;
+ } else { // server side
+ encCipher.init(Cipher.ENCRYPT_MODE,
+ new SecretKeySpec(server_key, 0, key_size, algName),
+ serverIV);
+ decCipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(client_key, 0, key_size, algName),
+ clientIV);
+ mac_write_secret = server_mac_secret;
+ mac_read_secret = client_mac_secret;
+ }
+ if (hashName.equals("MD5")) {
+ pad_1 = SSLv3Constants.MD5pad1;
+ pad_2 = SSLv3Constants.MD5pad2;
+ } else {
+ pad_1 = SSLv3Constants.SHApad1;
+ pad_2 = SSLv3Constants.SHApad2;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AlertException(AlertProtocol.INTERNAL_ERROR,
+ new SSLProtocolException(
+ "Error during computation of security parameters"));
+ }
+ }
+
+ /**
+ * Creates the GenericStreamCipher or GenericBlockCipher
+ * data structure for specified data of specified type.
+ * @throws AlertException if alert was occured.
+ */
+ protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) {
+ try {
+ int content_mac_length = len + hash_size;
+ int padding_length = is_block_cipher
+ ? padding_length =
+ ((8 - (++content_mac_length & 0x07)) & 0x07)
+ : 0;
+ byte[] res = new byte[content_mac_length + padding_length];
+ System.arraycopy(fragment, offset, res, 0, len);
+
+ mac_material_part[0] = type;
+ mac_material_part[1] = (byte) ((0x00FF00 & len) >> 8);
+ mac_material_part[2] = (byte) (0x0000FF & len);
+
+ messageDigest.update(mac_write_secret);
+ messageDigest.update(pad_1);
+ messageDigest.update(write_seq_num);
+ messageDigest.update(mac_material_part);
+ messageDigest.update(fragment, offset, len);
+ byte[] digest = messageDigest.digest();
+ messageDigest.update(mac_write_secret);
+ messageDigest.update(pad_2);
+ messageDigest.update(digest);
+ digest = messageDigest.digest();
+ System.arraycopy(digest, 0, res, len, hash_size);
+
+ //if (logger != null) {
+ // logger.println("MAC Material:");
+ // logger.print(write_seq_num);
+ // logger.print(mac_material_header);
+ // logger.print(fragment, offset, len);
+ //}
+
+ if (is_block_cipher) {
+ // do padding:
+ Arrays.fill(res, content_mac_length-1,
+ res.length, (byte) (padding_length));
+ }
+ if (logger != null) {
+ logger.println("SSLRecordProtocol.encrypt: "
+ + (is_block_cipher
+ ? "GenericBlockCipher with padding["
+ +padding_length+"]:"
+ : "GenericStreamCipher:"));
+ logger.print(res);
+ }
+ byte[] rez = new byte[encCipher.getOutputSize(res.length)];
+ encCipher.update(res, 0, res.length, rez);
+ incSequenceNumber(write_seq_num);
+ return rez;
+ } catch (GeneralSecurityException e) {
+ e.printStackTrace();
+ throw new AlertException(AlertProtocol.INTERNAL_ERROR,
+ new SSLProtocolException("Error during the encryption"));
+ }
+ }
+
+ /**
+ * Retrieves the fragment of the Plaintext structure of
+ * the specified type from the provided data.
+ * @throws AlertException if alert was occured.
+ */
+ protected byte[] decrypt(byte type, byte[] fragment,
+ int offset, int len) {
+ // plain data of the Generic[Stream|Block]Cipher structure
+ byte[] data = decCipher.update(fragment, offset, len);
+ // the 'content' part of the structure
+ byte[] content;
+ if (is_block_cipher) {
+ // check padding
+ int padding_length = data[data.length-1];
+ for (int i=0; i<padding_length; i++) {
+ if (data[data.length-2-i] != padding_length) {
+ throw new AlertException(
+ AlertProtocol.DECRYPTION_FAILED,
+ new SSLProtocolException(
+ "Received message has bad padding"));
+ }
+ }
+ content = new byte[data.length - hash_size - padding_length - 1];
+ } else {
+ content = new byte[data.length - hash_size];
+ }
+
+ byte[] mac_value;
+
+ mac_material_part[0] = type;
+ mac_material_part[1] = (byte) ((0x00FF00 & content.length) >> 8);
+ mac_material_part[2] = (byte) (0x0000FF & content.length);
+
+ messageDigest.update(mac_read_secret);
+ messageDigest.update(pad_1);
+ messageDigest.update(read_seq_num);
+ messageDigest.update(mac_material_part);
+ messageDigest.update(data, 0, content.length);
+ mac_value = messageDigest.digest();
+ messageDigest.update(mac_read_secret);
+ messageDigest.update(pad_2);
+ messageDigest.update(mac_value);
+ mac_value = messageDigest.digest();
+
+ if (logger != null) {
+ logger.println("Decrypted:");
+ logger.print(data);
+ //logger.println("MAC Material:");
+ //logger.print(read_seq_num);
+ //logger.print(mac_material_header);
+ //logger.print(data, 0, content.length);
+ logger.println("Expected mac value:");
+ logger.print(mac_value);
+ }
+ // checking the mac value
+ for (int i=0; i<hash_size; i++) {
+ if (mac_value[i] != data[i+content.length]) {
+ throw new AlertException(AlertProtocol.BAD_RECORD_MAC,
+ new SSLProtocolException("Bad record MAC"));
+ }
+ }
+ System.arraycopy(data, 0, content, 0, content.length);
+ incSequenceNumber(read_seq_num);
+ return content;
+ }
+
+ /**
+ * Shutdownes the protocol. It will be impossiblke to use the instance
+ * after the calling of this method.
+ */
+ protected void shutdown() {
+ Arrays.fill(mac_write_secret, (byte) 0);
+ Arrays.fill(mac_read_secret, (byte) 0);
+ super.shutdown();
+ }
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateTLS.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateTLS.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateTLS.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ConnectionStateTLS.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+import java.security.GeneralSecurityException;
+import java.util.Arrays;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLProtocolException;
+
+/**
+ * This class incapsulates the operating environment of the TLS v1
+ * (http://www.ietf.org/rfc/rfc2246.txt) Record Protocol and provides
+ * relating encryption/decryption functionality.
+ * The work functionality is based on the security
+ * parameters negotiated during the handshake.
+ */
+public class ConnectionStateTLS extends ConnectionState {
+
+ // Precomputed prf label values:
+ // "key expansion".getBytes()
+ private static byte[] KEY_EXPANSION_LABEL = {
+ (byte) 0x6B, (byte) 0x65, (byte) 0x79, (byte) 0x20, (byte) 0x65,
+ (byte) 0x78, (byte) 0x70, (byte) 0x61, (byte) 0x6E, (byte) 0x73,
+ (byte) 0x69, (byte) 0x6F, (byte) 0x6E };
+
+ // "client write key".getBytes()
+ private static byte[] CLIENT_WRITE_KEY_LABEL = {
+ (byte) 0x63, (byte) 0x6C, (byte) 0x69, (byte) 0x65, (byte) 0x6E,
+ (byte) 0x74, (byte) 0x20, (byte) 0x77, (byte) 0x72, (byte) 0x69,
+ (byte) 0x74, (byte) 0x65, (byte) 0x20, (byte) 0x6B, (byte) 0x65,
+ (byte) 0x79 };
+
+ // "server write key".getBytes()
+ private static byte[] SERVER_WRITE_KEY_LABEL = {
+ (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65,
+ (byte) 0x72, (byte) 0x20, (byte) 0x77, (byte) 0x72, (byte) 0x69,
+ (byte) 0x74, (byte) 0x65, (byte) 0x20, (byte) 0x6B, (byte) 0x65,
+ (byte) 0x79 };
+
+ // "IV block".getBytes()
+ private static byte[] IV_BLOCK_LABEL = {
+ (byte) 0x49, (byte) 0x56, (byte) 0x20, (byte) 0x62, (byte) 0x6C,
+ (byte) 0x6F, (byte) 0x63, (byte) 0x6B };
+
+ // MACs to create and check the message integrity info
+ private final Mac encMac;
+ private final Mac decMac;
+
+ // Once created permanently used array:
+ // is used to create the header of the MAC material value:
+ // 5 == 1(TLSCompressed.type) + 2(TLSCompressed.version) +
+ // 2(TLSCompressed.length)
+ private final byte[] mac_material_header = new byte[] {0, 3, 1, 0, 0};
+
+ /**
+ * Creates the instance of TLS v1 Connection State. All of the
+ * security parameters are provided by session object.
+ * @param session: the sessin object which incapsulates
+ * all of the security parameters established by handshake protocol.
+ * The key calculation for the state is done according
+ * to the TLS v 1.0 Protocol specification.
+ * (http://www.ietf.org/rfc/rfc2246.txt)
+ */
+ protected ConnectionStateTLS(SSLSessionImpl session) {
+ try {
+ CipherSuite cipherSuite = session.cipherSuite;
+
+ hash_size = cipherSuite.getMACLength();
+ boolean is_exportabe = cipherSuite.isExportable();
+ int key_size = (is_exportabe)
+ ? cipherSuite.keyMaterial
+ : cipherSuite.expandedKeyMaterial;
+ int iv_size = cipherSuite.getBlockSize();
+
+ String algName = cipherSuite.getBulkEncryptionAlgorithm();
+ String macName = cipherSuite.getHmacName();
+ if (logger != null) {
+ logger.println("ConnectionStateTLS.create:");
+ logger.println(" cipher suite name: "
+ + cipherSuite.getName());
+ logger.println(" encryption alg name: " + algName);
+ logger.println(" mac alg name: " + macName);
+ logger.println(" hash size: " + hash_size);
+ logger.println(" block size: " + iv_size);
+ logger.println(" IV size (== block size):" + iv_size);
+ logger.println(" key size: " + key_size);
+ }
+
+ byte[] clientRandom = session.clientRandom;
+ byte[] serverRandom = session.serverRandom;
+ // so we need PRF value of size of
+ // 2*hash_size + 2*key_size + 2*iv_size
+ byte[] key_block = new byte[2*hash_size + 2*key_size + 2*iv_size];
+ byte[] seed = new byte[clientRandom.length + serverRandom.length];
+ System.arraycopy(serverRandom, 0, seed, 0, serverRandom.length);
+ System.arraycopy(clientRandom, 0, seed, serverRandom.length,
+ clientRandom.length);
+
+ PRF.computePRF(key_block, session.master_secret,
+ KEY_EXPANSION_LABEL, seed);
+
+ byte[] client_mac_secret = new byte[hash_size];
+ byte[] server_mac_secret = new byte[hash_size];
+ byte[] client_key = new byte[key_size];
+ byte[] server_key = new byte[key_size];
+
+ boolean is_client = !session.isServer;
+
+ is_block_cipher = (iv_size > 0);
+ // do not count, as block_size is always 8
+ // block_size = iv_size;
+
+ System.arraycopy(key_block, 0, client_mac_secret, 0, hash_size);
+ System.arraycopy(key_block, hash_size,
+ server_mac_secret, 0, hash_size);
+ System.arraycopy(key_block, 2*hash_size, client_key, 0, key_size);
+ System.arraycopy(key_block, 2*hash_size+key_size,
+ server_key, 0, key_size);
+
+ IvParameterSpec clientIV = null;
+ IvParameterSpec serverIV = null;
+
+ if (is_exportabe) {
+ System.arraycopy(clientRandom, 0,
+ seed, 0, clientRandom.length);
+ System.arraycopy(serverRandom, 0,
+ seed, clientRandom.length, serverRandom.length);
+ byte[] final_client_key =
+ new byte[cipherSuite.expandedKeyMaterial];
+ byte[] final_server_key =
+ new byte[cipherSuite.expandedKeyMaterial];
+ PRF.computePRF(final_client_key, client_key,
+ CLIENT_WRITE_KEY_LABEL, seed);
+ PRF.computePRF(final_server_key, server_key,
+ SERVER_WRITE_KEY_LABEL, seed);
+ client_key = final_client_key;
+ server_key = final_server_key;
+ if (is_block_cipher) {
+ byte[] iv_block = new byte[2*iv_size];
+ PRF.computePRF(iv_block, null, IV_BLOCK_LABEL, seed);
+ clientIV = new IvParameterSpec(iv_block, 0, iv_size);
+ serverIV = new IvParameterSpec(iv_block, iv_size, iv_size);
+ }
+ } else if (is_block_cipher) {
+ clientIV = new IvParameterSpec(key_block,
+ 2*(hash_size+key_size), iv_size);
+ serverIV = new IvParameterSpec(key_block,
+ 2*(hash_size+key_size)+iv_size, iv_size);
+ }
+
+ if (logger != null) {
+ logger.println("is exportable: "+is_exportabe);
+ logger.println("master_secret");
+ logger.print(session.master_secret);
+ logger.println("client_random");
+ logger.print(clientRandom);
+ logger.println("server_random");
+ logger.print(serverRandom);
+ //logger.println("key_block");
+ //logger.print(key_block);
+ logger.println("client_mac_secret");
+ logger.print(client_mac_secret);
+ logger.println("server_mac_secret");
+ logger.print(server_mac_secret);
+ logger.println("client_key");
+ logger.print(client_key);
+ logger.println("server_key");
+ logger.print(server_key);
+ if (clientIV == null) {
+ logger.println("no IV.");
+ } else {
+ logger.println("client_iv");
+ logger.print(clientIV.getIV());
+ logger.println("server_iv");
+ logger.print(serverIV.getIV());
+ }
+ }
+
+ encCipher = Cipher.getInstance(algName);
+ decCipher = Cipher.getInstance(algName);
+ encMac = Mac.getInstance(macName);
+ decMac = Mac.getInstance(macName);
+
+ if (is_client) { // client side
+ encCipher.init(Cipher.ENCRYPT_MODE,
+ new SecretKeySpec(client_key, algName), clientIV);
+ decCipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(server_key, algName), serverIV);
+ encMac.init(new SecretKeySpec(client_mac_secret, macName));
+ decMac.init(new SecretKeySpec(server_mac_secret, macName));
+ } else { // server side
+ encCipher.init(Cipher.ENCRYPT_MODE,
+ new SecretKeySpec(server_key, algName), serverIV);
+ decCipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(client_key, algName), clientIV);
+ encMac.init(new SecretKeySpec(server_mac_secret, macName));
+ decMac.init(new SecretKeySpec(client_mac_secret, macName));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AlertException(AlertProtocol.INTERNAL_ERROR,
+ new SSLProtocolException(
+ "Error during computation of security parameters"));
+ }
+ }
+
+ /**
+ * Creates the GenericStreamCipher or GenericBlockCipher
+ * data structure for specified data of specified type.
+ * @throws AlertException if alert was occured.
+ */
+ protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) {
+ try {
+ int content_mac_length = len + hash_size;
+ int padding_length = is_block_cipher
+ ? ((8 - (++content_mac_length & 0x07)) & 0x07)
+ : 0;
+ byte[] res = new byte[content_mac_length + padding_length];
+ System.arraycopy(fragment, offset, res, 0, len);
+
+ mac_material_header[0] = type;
+ mac_material_header[3] = (byte) ((0x00FF00 & len) >> 8);
+ mac_material_header[4] = (byte) (0x0000FF & len);
+
+ encMac.update(write_seq_num);
+ encMac.update(mac_material_header);
+ encMac.update(fragment, offset, len);
+ encMac.doFinal(res, len);
+
+ //if (logger != null) {
+ // logger.println("MAC Material:");
+ // logger.print(write_seq_num);
+ // logger.print(mac_material_header);
+ // logger.print(fragment, offset, len);
+ //}
+
+ if (is_block_cipher) {
+ // do padding:
+ Arrays.fill(res, content_mac_length-1,
+ res.length, (byte) (padding_length));
+ }
+ if (logger != null) {
+ logger.println("SSLRecordProtocol.do_encryption: Generic"
+ + (is_block_cipher
+ ? "BlockCipher with padding["+padding_length+"]:"
+ : "StreamCipher:"));
+ logger.print(res);
+ }
+ byte[] rez = new byte[encCipher.getOutputSize(res.length)];
+ // We should not call just doFinal because it reinitialize
+ // the cipher, but as says rfc 2246:
+ // "For stream ciphers that do not use a synchronization
+ // vector (such as RC4), the stream cipher state from the end
+ // of one record is simply used on the subsequent packet."
+ // and for block ciphers:
+ // "The IV for subsequent records is the last ciphertext block from
+ // the previous record."
+ // i.e. we should keep the cipher state.
+ encCipher.update(res, 0, res.length, rez);
+ incSequenceNumber(write_seq_num);
+ return rez;
+ } catch (GeneralSecurityException e) {
+ e.printStackTrace();
+ throw new AlertException(AlertProtocol.INTERNAL_ERROR,
+ new SSLProtocolException("Error during the encryption"));
+ }
+ }
+
+ /**
+ * Retrieves the fragment of the Plaintext structure of
+ * the specified type from the provided data representing
+ * the Generic[Stream|Block]Cipher structure.
+ * @throws AlertException if alert was occured.
+ */
+ protected byte[] decrypt(byte type, byte[] fragment,
+ int offset, int len) {
+ // plain data of the Generic[Stream|Block]Cipher structure
+ byte[] data = decCipher.update(fragment, offset, len);
+ // the 'content' part of the structure
+ byte[] content;
+ if (is_block_cipher) {
+ // check padding
+ int padding_length = data[data.length-1];
+ for (int i=0; i<padding_length; i++) {
+ if (data[data.length-2-i] != padding_length) {
+ throw new AlertException(
+ AlertProtocol.DECRYPTION_FAILED,
+ new SSLProtocolException(
+ "Received message has bad padding"));
+ }
+ }
+ content = new byte[data.length - hash_size - padding_length - 1];
+ } else {
+ content = new byte[data.length - hash_size];
+ }
+
+ mac_material_header[0] = type;
+ mac_material_header[3] = (byte) ((0x00FF00 & content.length) >> 8);
+ mac_material_header[4] = (byte) (0x0000FF & content.length);
+
+ decMac.update(read_seq_num);
+ decMac.update(mac_material_header);
+ decMac.update(data, 0, content.length); // mac.update(fragment);
+ byte[] mac_value = decMac.doFinal();
+ if (logger != null) {
+ logger.println("Decrypted:");
+ logger.print(data);
+ //logger.println("MAC Material:");
+ //logger.print(read_seq_num);
+ //logger.print(mac_material_header);
+ //logger.print(data, 0, content.length);
+ logger.println("Expected mac value:");
+ logger.print(mac_value);
+ }
+ // checking the mac value
+ for (int i=0; i<hash_size; i++) {
+ if (mac_value[i] != data[i+content.length]) {
+ throw new AlertException(AlertProtocol.BAD_RECORD_MAC,
+ new SSLProtocolException("Bad record MAC"));
+ }
+ }
+ System.arraycopy(data, 0, content, 0, content.length);
+ incSequenceNumber(read_seq_num);
+ return content;
+ }
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ContentType.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ContentType.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ContentType.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/ContentType.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Alexander Y. Kleymenov
+ * @version $Revision$
+ */
+
+package org.apache.harmony.security.provider.jsse;
+
+/**
+ * This class incapsulates the constants determining the
+ * types of SSL/TLS record's content data.
+ * Constant values are taken according to the TLS v1 specification
+ * (http://www.ietf.org/rfc/rfc2246.txt).
+ */
+public class ContentType {
+
+ /**
+ * Identifies change cipher spec message
+ */
+ protected static final byte CHANGE_CIPHER_SPEC = 20;
+
+ /**
+ * Identifies alert message
+ */
+ protected static final byte ALERT = 21;
+
+ /**
+ * Identifies handshake message
+ */
+ protected static final byte HANDSHAKE = 22;
+
+ /**
+ * Identifies application data message
+ */
+ protected static final byte APPLICATION_DATA = 23;
+
+}
+
Added: incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/DHParameters.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/DHParameters.java?rev=423275&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/DHParameters.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/x-net/src/main/java/org/apache/harmony/security/provider/jsse/DHParameters.java Tue Jul 18 15:50:12 2006
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author Boris Kuznetsov
+ * @version $Revision$
+ */
+package org.apache.harmony.security.provider.jsse;
+
+/**
+ * This class contains well-known primes
+ */
+public class DHParameters {
+
+ // Well-known 512 bit prime
+ // http://news.hping.org/sci.crypt.archive/2370.html
+ private static byte[] prime512 = new byte[] { (byte) 0xF5, (byte) 0x2A, (byte) 0xFF,
+ (byte) 0x3C, (byte) 0xE1, (byte) 0xB1, (byte) 0x29, (byte) 0x40,
+ (byte) 0x18, (byte) 0x11, (byte) 0x8D, (byte) 0x7C, (byte) 0x84,
+ (byte) 0xA7, (byte) 0x0A, (byte) 0x72, (byte) 0xD6, (byte) 0x86,
+ (byte) 0xC4, (byte) 0x03, (byte) 0x19, (byte) 0xC8, (byte) 0x07,
+ (byte) 0x29, (byte) 0x7A, (byte) 0xCA, (byte) 0x95, (byte) 0x0C,
+ (byte) 0xD9, (byte) 0x96, (byte) 0x9F, (byte) 0xAB, (byte) 0xD0,
+ (byte) 0x0A, (byte) 0x50, (byte) 0x9B, (byte) 0x02, (byte) 0x46,
+ (byte) 0xD3, (byte) 0x08, (byte) 0x3D, (byte) 0x66, (byte) 0xA4,
+ (byte) 0x5D, (byte) 0x41, (byte) 0x9F, (byte) 0x9C, (byte) 0x7C,
+ (byte) 0xBD, (byte) 0x89, (byte) 0x4B, (byte) 0x22, (byte) 0x19,
+ (byte) 0x26, (byte) 0xBA, (byte) 0xAB, (byte) 0xA2, (byte) 0x5E,
+ (byte) 0xC3, (byte) 0x55, (byte) 0xE9, (byte) 0x2A, (byte) 0x05,
+ (byte) 0x5F };
+
+ // Well-Known Group 1: A 768 bit prime rfc 2539
+ // (http://www.ietf.org/rfc/rfc2539.txt?number=2539)
+ private static byte[] primeGroup1 = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC9,
+ (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68,
+ (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62,
+ (byte) 0x8B, (byte) 0x80, (byte) 0xDC, (byte) 0x1C, (byte) 0xD1,
+ (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A,
+ (byte) 0x67, (byte) 0xCC, (byte) 0x74, (byte) 0x02, (byte) 0x0B,
+ (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13, (byte) 0x9B,
+ (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79,
+ (byte) 0x8E, (byte) 0x34, (byte) 0x04, (byte) 0xDD, (byte) 0xEF,
+ (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A,
+ (byte) 0x43, (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A,
+ (byte) 0x6D, (byte) 0xF2, (byte) 0x5F, (byte) 0x14, (byte) 0x37,
+ (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D,
+ (byte) 0x51, (byte) 0xC2, (byte) 0x45, (byte) 0xE4, (byte) 0x85,
+ (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E, (byte) 0x7E,
+ (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9,
+ (byte) 0xA6, (byte) 0x3A, (byte) 0x36, (byte) 0x20, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF };
+
+ // Well-Known Group 2: A 1024 bit prime rfc 2539
+ // (http://www.ietf.org/rfc/rfc2539.txt?number=2539)
+ private static byte[] primeGroup2 = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC9,
+ (byte) 0x0F, (byte) 0xDA, (byte) 0xA2, (byte) 0x21, (byte) 0x68,
+ (byte) 0xC2, (byte) 0x34, (byte) 0xC4, (byte) 0xC6, (byte) 0x62,
+ (byte) 0x8B, (byte) 0x80, (byte) 0xDC, (byte) 0x1C, (byte) 0xD1,
+ (byte) 0x29, (byte) 0x02, (byte) 0x4E, (byte) 0x08, (byte) 0x8A,
+ (byte) 0x67, (byte) 0xCC, (byte) 0x74, (byte) 0x02, (byte) 0x0B,
+ (byte) 0xBE, (byte) 0xA6, (byte) 0x3B, (byte) 0x13, (byte) 0x9B,
+ (byte) 0x22, (byte) 0x51, (byte) 0x4A, (byte) 0x08, (byte) 0x79,
+ (byte) 0x8E, (byte) 0x34, (byte) 0x04, (byte) 0xDD, (byte) 0xEF,
+ (byte) 0x95, (byte) 0x19, (byte) 0xB3, (byte) 0xCD, (byte) 0x3A,
+ (byte) 0x43, (byte) 0x1B, (byte) 0x30, (byte) 0x2B, (byte) 0x0A,
+ (byte) 0x6D, (byte) 0xF2, (byte) 0x5F, (byte) 0x14, (byte) 0x37,
+ (byte) 0x4F, (byte) 0xE1, (byte) 0x35, (byte) 0x6D, (byte) 0x6D,
+ (byte) 0x51, (byte) 0xC2, (byte) 0x45, (byte) 0xE4, (byte) 0x85,
+ (byte) 0xB5, (byte) 0x76, (byte) 0x62, (byte) 0x5E, (byte) 0x7E,
+ (byte) 0xC6, (byte) 0xF4, (byte) 0x4C, (byte) 0x42, (byte) 0xE9,
+ (byte) 0xA6, (byte) 0x37, (byte) 0xED, (byte) 0x6B, (byte) 0x0B,
+ (byte) 0xFF, (byte) 0x5C, (byte) 0xB6, (byte) 0xF4, (byte) 0x06,
+ (byte) 0xB7, (byte) 0xED, (byte) 0xEE, (byte) 0x38, (byte) 0x6B,
+ (byte) 0xFB, (byte) 0x5A, (byte) 0x89, (byte) 0x9F, (byte) 0xA5,
+ (byte) 0xAE, (byte) 0x9F, (byte) 0x24, (byte) 0x11, (byte) 0x7C,
+ (byte) 0x4B, (byte) 0x1F, (byte) 0xE6, (byte) 0x49, (byte) 0x28,
+ (byte) 0x66, (byte) 0x51, (byte) 0xEC, (byte) 0xE6, (byte) 0x53,
+ (byte) 0x81, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
+ (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF
+ };
+
+ private static byte[] prime;
+
+ static {
+//TODO set prime depand on some system or security property
+ prime = prime512;
+ }
+
+ /**
+ * Returns prime bytes
+ * @return
+ */
+ public static byte[] getPrime() {
+ return prime;
+ }
+}
\ No newline at end of file