blob: 582d31695bef69c672589d01f942b576af82b503 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.xnet.provider.jsse;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLPermission;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionBindingEvent;
import javax.net.ssl.SSLSessionBindingListener;
import javax.net.ssl.SSLSessionContext;
import libcore.base.Objects;
/**
*
* SSLSession implementation
*
* @see javax.net.ssl.SSLSession
*/
public class SSLSessionImpl implements SSLSession, Cloneable {
/**
* Session object reporting an invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
*/
public static final SSLSessionImpl NULL_SESSION = new SSLSessionImpl(null);
/**
* Container class for the 'value' map's keys.
*/
private static final class ValueKey {
final String name;
final AccessControlContext acc;
ValueKey(String name) {
super();
this.name = name;
this.acc = AccessController.getContext();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((acc == null) ? 0 : acc.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof ValueKey))
return false;
ValueKey other = (ValueKey) obj;
if (acc == null) {
if (other.acc != null)
return false;
} else if (!acc.equals(other.acc))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
private long creationTime;
private boolean isValid = true;
private Map<ValueKey, Object> values = new HashMap<ValueKey, Object>();
/**
* ID of the session
*/
byte[] id;
/**
* Last time the session was accessed
*/
long lastAccessedTime;
/**
* Protocol used in the session
*/
ProtocolVersion protocol;
/**
* CipherSuite used in the session
*/
CipherSuite cipherSuite;
/**
* Context of the session
*/
// BEGIN android-changed
SSLSessionContext context;
// END android-changed
/**
* certificates were sent to the peer
*/
X509Certificate[] localCertificates;
/**
* Peer certificates
*/
X509Certificate[] peerCertificates;
/**
* Peer host name
*/
private String peerHost;
/**
* Peer port number
*/
private int peerPort = -1;
/**
* Master secret
*/
byte[] master_secret;
/**
* clientRandom
*/
byte[] clientRandom;
/**
* serverRandom
*/
byte[] serverRandom;
/**
* True if this entity is considered the server
*/
final boolean isServer;
/**
* Creates SSLSession implementation
*
* @param cipher_suite
* @param sr
*/
public SSLSessionImpl(CipherSuite cipher_suite, SecureRandom sr) {
creationTime = System.currentTimeMillis();
lastAccessedTime = creationTime;
if (cipher_suite == null) {
this.cipherSuite = CipherSuite.SSL_NULL_WITH_NULL_NULL;
id = new byte[0];
isServer = false;
isValid = false;
} else {
this.cipherSuite = cipher_suite;
id = new byte[32];
sr.nextBytes(id);
long time = creationTime / 1000;
id[28] = (byte) ((time & 0xFF000000) >>> 24);
id[29] = (byte) ((time & 0x00FF0000) >>> 16);
id[30] = (byte) ((time & 0x0000FF00) >>> 8);
id[31] = (byte) ((time & 0x000000FF));
isServer = true;
}
}
/**
* Creates SSLSession implementation
*
* @param sr
*/
public SSLSessionImpl(SecureRandom sr) {
this(null, sr);
}
public int getApplicationBufferSize() {
return SSLRecordProtocol.MAX_DATA_LENGTH;
}
public String getCipherSuite() {
return cipherSuite.getName();
}
public long getCreationTime() {
return creationTime;
}
public byte[] getId() {
return id;
}
public long getLastAccessedTime() {
return lastAccessedTime;
}
public Certificate[] getLocalCertificates() {
return localCertificates;
}
public Principal getLocalPrincipal() {
if (localCertificates != null && localCertificates.length > 0) {
return localCertificates[0].getSubjectX500Principal();
}
return null;
}
public int getPacketBufferSize() {
return SSLRecordProtocol.MAX_SSL_PACKET_SIZE;
}
public javax.security.cert.X509Certificate[] getPeerCertificateChain()
throws SSLPeerUnverifiedException {
if (peerCertificates == null) {
throw new SSLPeerUnverifiedException("No peer certificate");
}
javax.security.cert.X509Certificate[] certs = new javax.security.cert.X509Certificate[peerCertificates.length];
for (int i = 0; i < certs.length; i++) {
try {
certs[i] = javax.security.cert.X509Certificate.getInstance(peerCertificates[i]
.getEncoded());
} catch (javax.security.cert.CertificateException e) {
} catch (CertificateEncodingException e) {
}
}
return certs;
}
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
if (peerCertificates == null) {
throw new SSLPeerUnverifiedException("No peer certificate");
}
return peerCertificates;
}
public String getPeerHost() {
return peerHost;
}
public int getPeerPort() {
return peerPort;
}
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
if (peerCertificates == null) {
throw new SSLPeerUnverifiedException("No peer certificate");
}
return peerCertificates[0].getSubjectX500Principal();
}
public String getProtocol() {
return (protocol == null) ? "NONE" : protocol.name;
}
public SSLSessionContext getSessionContext() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new SSLPermission("getSSLSessionContext"));
}
return context;
}
public Object getValue(String name) {
if (name == null) {
throw new IllegalArgumentException("Parameter is null");
}
return values.get(new ValueKey(name));
}
public String[] getValueNames() {
final Vector<String> v = new Vector<String>();
final AccessControlContext currAcc = AccessController.getContext();
for (ValueKey key : values.keySet()) {
if (Objects.equal(currAcc, key.acc)) {
v.add(key.name);
}
}
return v.toArray(new String[v.size()]);
}
public void invalidate() {
isValid = false;
context = null;
}
public boolean isValid() {
if (isValid && context != null && context.getSessionTimeout() != 0
&& lastAccessedTime + context.getSessionTimeout() > System.currentTimeMillis()) {
isValid = false;
}
return isValid;
}
public void putValue(String name, Object value) {
if (name == null || value == null) {
throw new IllegalArgumentException("Parameter is null");
}
Object old = values.put(new ValueKey(name), value);
if (value instanceof SSLSessionBindingListener) {
((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
}
if (old instanceof SSLSessionBindingListener) {
((SSLSessionBindingListener) old).valueUnbound(new SSLSessionBindingEvent(this, name));
}
}
public void removeValue(String name) {
if (name == null) {
throw new IllegalArgumentException("Parameter is null");
}
Object old = values.remove(new ValueKey(name));
if (old instanceof SSLSessionBindingListener) {
SSLSessionBindingListener listener = (SSLSessionBindingListener) old;
listener.valueUnbound(new SSLSessionBindingEvent(this, name));
}
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError(e);
}
}
/**
* Sets the address of the peer
*
* @param peerHost
* @param peerPort
*/
void setPeer(String peerHost, int peerPort) {
this.peerHost = peerHost;
this.peerPort = peerPort;
}
}