1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.xnet.provider.jsse;
19
20import java.security.AccessControlContext;
21import java.security.AccessController;
22import java.security.Principal;
23import java.security.SecureRandom;
24import java.security.cert.Certificate;
25import java.security.cert.CertificateEncodingException;
26import java.security.cert.X509Certificate;
27import java.util.HashMap;
28import java.util.Map;
29import java.util.Vector;
30
31import javax.net.ssl.SSLPeerUnverifiedException;
32import javax.net.ssl.SSLPermission;
33import javax.net.ssl.SSLSession;
34import javax.net.ssl.SSLSessionBindingEvent;
35import javax.net.ssl.SSLSessionBindingListener;
36import javax.net.ssl.SSLSessionContext;
37
38/**
39 *
40 * SSLSession implementation
41 *
42 * @see javax.net.ssl.SSLSession
43 */
44public class SSLSessionImpl implements SSLSession, Cloneable  {
45
46    /**
47     * Session object reporting an invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
48     */
49    public static final SSLSessionImpl NULL_SESSION = new SSLSessionImpl(null);
50
51    /**
52     * Container class for the 'value' map's keys.
53     */
54    private static final class ValueKey {
55        final String name;
56        final AccessControlContext acc;
57
58        ValueKey(String name) {
59            super();
60            this.name = name;
61            this.acc = AccessController.getContext();
62        }
63
64        @Override
65        public int hashCode() {
66            final int prime = 31;
67            int result = 1;
68            result = prime * result + ((acc == null) ? 0 : acc.hashCode());
69            result = prime * result + ((name == null) ? 0 : name.hashCode());
70            return result;
71        }
72
73        @Override
74        public boolean equals(Object obj) {
75            if (this == obj)
76                return true;
77            if (obj == null)
78                return false;
79            if (!(obj instanceof ValueKey))
80                return false;
81            ValueKey other = (ValueKey) obj;
82            if (acc == null) {
83                if (other.acc != null)
84                    return false;
85            } else if (!acc.equals(other.acc))
86                return false;
87            if (name == null) {
88                if (other.name != null)
89                    return false;
90            } else if (!name.equals(other.name))
91                return false;
92            return true;
93        }
94    }
95
96    private long creationTime;
97    private boolean isValid = true;
98    private Map<ValueKey, Object> values = new HashMap<ValueKey, Object>();
99
100    /**
101     * ID of the session
102     */
103    byte[] id;
104
105    /**
106     * Last time the session was accessed
107     */
108    long lastAccessedTime;
109
110    /**
111     * Protocol used in the session
112     */
113    ProtocolVersion protocol;
114
115    /**
116     * CipherSuite used in the session
117     */
118    CipherSuite cipherSuite;
119
120    /**
121     * Context of the session
122     */
123// BEGIN android-changed
124    SSLSessionContext context;
125// END android-changed
126
127    /**
128     * certificates were sent to the peer
129     */
130    X509Certificate[] localCertificates;
131
132    /**
133     * Peer certificates
134     */
135    X509Certificate[] peerCertificates;
136
137    /**
138     * Peer host name
139     */
140    private String peerHost;
141
142    /**
143     * Peer port number
144     */
145    private int peerPort = -1;
146
147    /**
148     * Master secret
149     */
150    byte[] master_secret;
151
152    /**
153     * clientRandom
154     */
155    byte[] clientRandom;
156
157    /**
158     * serverRandom
159     */
160    byte[] serverRandom;
161
162    /**
163     * True if this entity is considered the server
164     */
165    final boolean isServer;
166
167    /**
168     * Creates SSLSession implementation
169     *
170     * @param cipher_suite
171     * @param sr
172     */
173    public SSLSessionImpl(CipherSuite cipher_suite, SecureRandom sr) {
174        creationTime = System.currentTimeMillis();
175        lastAccessedTime = creationTime;
176        if (cipher_suite == null) {
177            this.cipherSuite = CipherSuite.TLS_NULL_WITH_NULL_NULL;
178            id = new byte[0];
179            isServer = false;
180        } else {
181            this.cipherSuite = cipher_suite;
182            id = new byte[32];
183            sr.nextBytes(id);
184            long time = creationTime / 1000;
185            id[28] = (byte) ((time & 0xFF000000) >>> 24);
186            id[29] = (byte) ((time & 0x00FF0000) >>> 16);
187            id[30] = (byte) ((time & 0x0000FF00) >>> 8);
188            id[31] = (byte) ((time & 0x000000FF));
189            isServer = true;
190        }
191
192    }
193
194    /**
195     * Creates SSLSession implementation
196     *
197     * @param sr
198     */
199    public SSLSessionImpl(SecureRandom sr) {
200        this(null, sr);
201    }
202
203    public int getApplicationBufferSize() {
204        return SSLRecordProtocol.MAX_DATA_LENGTH;
205    }
206
207    public String getCipherSuite() {
208        return cipherSuite.getName();
209    }
210
211    public long getCreationTime() {
212        return creationTime;
213    }
214
215    public byte[] getId() {
216        return id;
217    }
218
219    public long getLastAccessedTime() {
220        return lastAccessedTime;
221    }
222
223    public Certificate[] getLocalCertificates() {
224        return localCertificates;
225    }
226
227    public Principal getLocalPrincipal() {
228        if (localCertificates != null && localCertificates.length > 0) {
229            return localCertificates[0].getSubjectX500Principal();
230        }
231        return null;
232    }
233
234    public int getPacketBufferSize() {
235        return SSLRecordProtocol.MAX_SSL_PACKET_SIZE;
236    }
237
238    public javax.security.cert.X509Certificate[] getPeerCertificateChain()
239            throws SSLPeerUnverifiedException {
240        if (peerCertificates == null) {
241            throw new SSLPeerUnverifiedException("No peer certificate");
242        }
243        javax.security.cert.X509Certificate[] certs = new javax.security.cert.X509Certificate[peerCertificates.length];
244        for (int i = 0; i < certs.length; i++) {
245            try {
246                certs[i] = javax.security.cert.X509Certificate.getInstance(peerCertificates[i]
247                        .getEncoded());
248            } catch (javax.security.cert.CertificateException e) {
249            } catch (CertificateEncodingException e) {
250            }
251        }
252        return certs;
253    }
254
255    public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
256        if (peerCertificates == null) {
257            throw new SSLPeerUnverifiedException("No peer certificate");
258        }
259        return peerCertificates;
260    }
261
262    public String getPeerHost() {
263        return peerHost;
264    }
265
266    public int getPeerPort() {
267        return peerPort;
268    }
269
270    public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
271        if (peerCertificates == null) {
272            throw new SSLPeerUnverifiedException("No peer certificate");
273        }
274        return peerCertificates[0].getSubjectX500Principal();
275    }
276
277    public String getProtocol() {
278        return protocol.name;
279    }
280
281    public SSLSessionContext getSessionContext() {
282        SecurityManager sm = System.getSecurityManager();
283        if (sm != null) {
284            sm.checkPermission(new SSLPermission("getSSLSessionContext"));
285        }
286        return context;
287    }
288
289    public Object getValue(String name) {
290        if (name == null) {
291            throw new IllegalArgumentException("Parameter is null");
292        }
293        return values.get(new ValueKey(name));
294    }
295
296    public String[] getValueNames() {
297        final Vector<String> v = new Vector<String>();
298        final AccessControlContext currAcc = AccessController.getContext();
299        for (ValueKey key : values.keySet()) {
300            if ((currAcc == null && key.acc == null)
301                    || (currAcc != null && currAcc.equals(key.acc))) {
302                v.add(key.name);
303            }
304        }
305        return v.toArray(new String[v.size()]);
306    }
307
308    public void invalidate() {
309        isValid = false;
310    }
311
312    public boolean isValid() {
313        if (isValid && context != null && context.getSessionTimeout() != 0
314                && lastAccessedTime + context.getSessionTimeout() > System.currentTimeMillis()) {
315            isValid = false;
316        }
317        return isValid;
318    }
319
320    public void putValue(String name, Object value) {
321        if (name == null || value == null) {
322            throw new IllegalArgumentException("Parameter is null");
323        }
324        Object old = values.put(new ValueKey(name), value);
325        if (value instanceof SSLSessionBindingListener) {
326            ((SSLSessionBindingListener) value).valueBound(new SSLSessionBindingEvent(this, name));
327        }
328        if (old instanceof SSLSessionBindingListener) {
329            ((SSLSessionBindingListener) old).valueUnbound(new SSLSessionBindingEvent(this, name));
330        }
331
332    }
333
334    public void removeValue(String name) {
335        if (name == null) {
336            throw new IllegalArgumentException("Parameter is null");
337        }
338        Object old = values.remove(new ValueKey(name));
339        if (old instanceof SSLSessionBindingListener) {
340            SSLSessionBindingListener listener = (SSLSessionBindingListener) old;
341            listener.valueUnbound(new SSLSessionBindingEvent(this, name));
342        }
343    }
344
345    @Override
346    public Object clone() {
347        try {
348            return super.clone();
349        } catch (CloneNotSupportedException e) {
350            throw new AssertionError(e);
351        }
352    }
353
354    /**
355     * Sets the address of the peer
356     *
357     * @param peerHost
358     * @param peerPort
359     */
360    void setPeer(String peerHost, int peerPort) {
361        this.peerHost = peerHost;
362        this.peerPort = peerPort;
363    }
364}
365