/* * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.ssl; import java.io.*;import java.net.*;import java.util.Enumeration;import java.util.Hashtable;import java.util.Vector;import java.util.Arrays;import java.util.Collection; import java.security.Principal;import java.security.PrivateKey;import java.security.SecureRandom;import java.security.cert.X509Certificate;import java.security.cert.CertificateEncodingException; import javax.crypto.SecretKey; import javax.net.ssl.SSLSession;import javax.net.ssl.SSLSessionContext;import javax.net.ssl.SSLSessionBindingListener;import javax.net.ssl.SSLSessionBindingEvent;import javax.net.ssl.SSLPeerUnverifiedException;import javax.net.ssl.SSLSession;import javax.net.ssl.SSLPermission;import javax.net.ssl.SSLException;import javax.net.ssl.ExtendedSSLSession; import javax.security.auth.x500.X500Principal; import static sun.security.ssl.CipherSuite.*;import static sun.security.ssl.CipherSuite.KeyExchange.*; /** * Implements the SSL session interface, and exposes the session context * which is maintained by SSL servers. * * <P> Servers have the ability to manage the sessions associated with * their authentication context(s). They can do this by enumerating the * IDs of the sessions which are cached, examining those sessions, and then * perhaps invalidating a given session so that it can't be used again. * If servers do not explicitly manage the cache, sessions will linger * until memory is low enough that the runtime environment purges cache * entries automatically to reclaim space. * * <P><em> The only reason this class is not package-private is that * there's no other public way to get at the server session context which * is associated with any given authentication context. </em> * * @author David Brownell */final class SSLSessionImpl extends ExtendedSSLSession { /* * we only really need a single null session */ static final SSLSessionImpl nullSession = new SSLSessionImpl(); // compression methods private static final byte compression_null = 0; /* * The state of a single session, as described in section 7.1 * of the SSLv3 spec. */ private final ProtocolVersion protocolVersion; private final SessionId sessionId; private X509Certificate[] peerCerts; private byte compressionMethod; private CipherSuite cipherSuite; private SecretKey masterSecret; /* * Information not part of the SSLv3 protocol spec, but used * to support session management policies. */ private final long creationTime = System.currentTimeMillis(); private long lastUsedTime = 0; private final String host; private final int port; private SSLSessionContextImpl context; private int sessionCount; private boolean invalidated; private X509Certificate[] localCerts; private PrivateKey localPrivateKey; private String[] localSupportedSignAlgs; private String[] peerSupportedSignAlgs; // Principals for non-certificate based cipher suites private Principal peerPrincipal; private Principal localPrincipal; /* * We count session creations, eventually for statistical data but * also since counters make shorter debugging IDs than the big ones * we use in the protocol for uniqueness-over-time. */ private static volatile int counter = 0; /* * Use of session caches is globally enabled/disabled. */ private static boolean defaultRejoinable = true; /* Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); /* * Create a new non-rejoinable session, using the default (null) * cipher spec. This constructor returns a session which could * be used either by a client or by a server, as a connection is * first opened and before handshaking begins. */ private SSLSessionImpl() { this(ProtocolVersion.NONE, CipherSuite.C_NULL, null, new SessionId(false, null), null, -1); } /* * Create a new session, using a given cipher spec. This will * be rejoinable if session caching is enabled; the constructor * is intended mostly for use by serves. */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection<SignatureAndHashAlgorithm> algorithms, SecureRandom generator, String host, int port) { this(protocolVersion, cipherSuite, algorithms, new SessionId(defaultRejoinable, generator), host, port); } /* * Record a new session, using a given cipher spec and session ID. */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection<SignatureAndHashAlgorithm> algorithms, SessionId id, String host, int port) { this.protocolVersion = protocolVersion; sessionId = id; peerCerts = null; compressionMethod = compression_null; this.cipherSuite = cipherSuite; masterSecret = null; this.host = host; this.port = port; sessionCount = ++counter; localSupportedSignAlgs = SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); if (debug != null && Debug.isOn("session")) { System.out.println("%% Initialized: " + this); } } void setMasterSecret(SecretKey secret) { if (masterSecret == null) { masterSecret = secret; } else { throw new RuntimeException("setMasterSecret() error"); } } /** * Returns the master secret ... treat with extreme caution! */ SecretKey getMasterSecret() { return masterSecret; } void setPeerCertificates(X509Certificate[] peer) { if (peerCerts == null) { peerCerts = peer; } } void setLocalCertificates(X509Certificate[] local) { localCerts = local; } void setLocalPrivateKey(PrivateKey privateKey) { localPrivateKey = privateKey; } void setPeerSupportedSignatureAlgorithms( Collection<SignatureAndHashAlgorithm> algorithms) { peerSupportedSignAlgs = SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); } /** * Set the peer principal. */ void setPeerPrincipal(Principal principal) { if (peerPrincipal == null) { peerPrincipal = principal; } } /** * Set the local principal. */ void setLocalPrincipal(Principal principal) { localPrincipal = principal; } /** * Returns true iff this session may be resumed ... sessions are * usually resumable. Security policies may suggest otherwise, * for example sessions that haven't been used for a while (say, * a working day) won't be resumable, and sessions might have a * maximum lifetime in any case. */ boolean isRejoinable() { return sessionId != null && sessionId.length() != 0 && !invalidated && isLocalAuthenticationValid(); } public synchronized boolean isValid() { return isRejoinable(); } /** * Check if the authentication used when establishing this session * is still valid. Returns true if no authentication was used */ boolean isLocalAuthenticationValid() { if (localPrivateKey != null) { try { // if the private key is no longer valid, getAlgorithm() // should throw an exception // (e.g. Smartcard has been removed from the reader) localPrivateKey.getAlgorithm(); } catch (Exception e) { invalidate(); return false; } } return true; } /** * Returns the ID for this session. The ID is fixed for the * duration of the session; neither it, nor its value, changes. */ public byte[] getId() { return sessionId.getId(); } /** * For server sessions, this returns the set of sessions which * are currently valid in this process. For client sessions, * this returns null. */ public SSLSessionContext getSessionContext() { /* * An interim security policy until we can do something * more specific in 1.2. Only allow trusted code (code which * can set system properties) to get an * SSLSessionContext. This is to limit the ability of code to * look up specific sessions or enumerate over them. Otherwise, * code can only get session objects from successful SSL * connections which implies that they must have had permission * to make the network connection in the first place. */ SecurityManager sm; if ((sm = System.getSecurityManager()) != null) { sm.checkPermission(new SSLPermission("getSSLSessionContext")); } return context; } SessionId getSessionId() { return sessionId; } /** * Returns the cipher spec in use on this session */ CipherSuite getSuite() { return cipherSuite; } /** * Resets the cipher spec in use on this session */ void setSuite(CipherSuite suite) { cipherSuite = suite; if (debug != null && Debug.isOn("session")) { System.out.println("%% Negotiating: " + this); } } /** * Returns the name of the cipher suite in use on this session */ public String getCipherSuite() { return getSuite().name; } ProtocolVersion getProtocolVersion() { return protocolVersion; } /** * Returns the standard name of the protocol in use on this session */ public String getProtocol() { return getProtocolVersion().name; } /** * Returns the compression technique used in this session */ byte getCompression() { return compressionMethod; } /** * Returns the hashcode for this session */ public int hashCode() { return sessionId.hashCode(); } /** * Returns true if sessions have same ids, false otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof SSLSessionImpl) { SSLSessionImpl sess = (SSLSessionImpl) obj; return (sessionId != null) && (sessionId.equals( sess.getSessionId())); } return false; } /** * Return the cert chain presented by the peer in the * java.security.cert format. * Note: This method can be used only when using certificate-based * cipher suites; using it with non-certificate-based cipher suites, * such as Kerberos, will throw an SSLPeerUnverifiedException. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { // // clone to preserve integrity of session ... caller can't // change record of peer identity even by accident, much // less do it intentionally. // if ((cipherSuite.keyExchange == K_KRB5) || (cipherSuite.keyExchange == K_KRB5_EXPORT)) { throw new SSLPeerUnverifiedException("no certificates expected" + " for Kerberos cipher suites"); } if (peerCerts == null) { throw new SSLPeerUnverifiedException("peer not authenticated"); } // Certs are immutable objects, therefore we don't clone them. // But do need to clone the array, so that nothing is inserted // into peerCerts. return (java.security.cert.Certificate[])peerCerts.clone(); } /** * Return the cert chain presented to the peer in the * java.security.cert format. * Note: This method is useful only when using certificate-based * cipher suites. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public java.security.cert.Certificate[] getLocalCertificates() { // // clone to preserve integrity of session ... caller can't // change record of peer identity even by accident, much // less do it intentionally. return (localCerts == null ? null : (java.security.cert.Certificate[])localCerts.clone()); } /** * Return the cert chain presented by the peer in the * javax.security.cert format. * Note: This method can be used only when using certificate-based * cipher suites; using it with non-certificate-based cipher suites, * such as Kerberos, will throw an SSLPeerUnverifiedException. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { // // clone to preserve integrity of session ... caller can't // change record of peer identity even by accident, much // less do it intentionally. // if ((cipherSuite.keyExchange == K_KRB5) || (cipherSuite.keyExchange == K_KRB5_EXPORT)) { throw new SSLPeerUnverifiedException("no certificates expected" + " for Kerberos cipher suites"); } if (peerCerts == null) { throw new SSLPeerUnverifiedException("peer not authenticated"); } javax.security.cert.X509Certificate[] certs; certs = new javax.security.cert.X509Certificate[peerCerts.length]; for (int i = 0; i < peerCerts.length; i++) { byte[] der = null; try { der = peerCerts[i].getEncoded(); certs[i] = javax.security.cert.X509Certificate.getInstance(der); } catch (CertificateEncodingException e) { throw new SSLPeerUnverifiedException(e.getMessage()); } catch (javax.security.cert.CertificateException e) { throw new SSLPeerUnverifiedException(e.getMessage()); } } return certs; } /** * Return the cert chain presented by the peer. * Note: This method can be used only when using certificate-based * cipher suites; using it with non-certificate-based cipher suites, * such as Kerberos, will throw an SSLPeerUnverifiedException. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public X509Certificate[] getCertificateChain() throws SSLPeerUnverifiedException { /* * clone to preserve integrity of session ... caller can't * change record of peer identity even by accident, much * less do it intentionally. */ if ((cipherSuite.keyExchange == K_KRB5) || (cipherSuite.keyExchange == K_KRB5_EXPORT)) { throw new SSLPeerUnverifiedException("no certificates expected" + " for Kerberos cipher suites"); } if (peerCerts != null) { return peerCerts.clone(); } else { throw new SSLPeerUnverifiedException("peer not authenticated"); } } /** * Returns the identity of the peer which was established as part of * defining the session. * * @return the peer's principal. Returns an X500Principal of the * end-entity certificate for X509-based cipher suites, and * Principal for Kerberos cipher suites. *Lines 1–500 of 832. Load more
/* * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.ssl; import java.io.*; import java.net.*; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import java.util.Arrays; import java.util.Collection; import java.security.Principal; import java.security.PrivateKey; import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.security.cert.CertificateEncodingException; import javax.crypto.SecretKey; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSessionBindingListener; import javax.net.ssl.SSLSessionBindingEvent; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLPermission; import javax.net.ssl.SSLException; import javax.net.ssl.ExtendedSSLSession; import javax.security.auth.x500.X500Principal; import static sun.security.ssl.CipherSuite.*; import static sun.security.ssl.CipherSuite.KeyExchange.*; /** * Implements the SSL session interface, and exposes the session context * which is maintained by SSL servers. * * <P> Servers have the ability to manage the sessions associated with * their authentication context(s). They can do this by enumerating the * IDs of the sessions which are cached, examining those sessions, and then * perhaps invalidating a given session so that it can't be used again. * If servers do not explicitly manage the cache, sessions will linger * until memory is low enough that the runtime environment purges cache * entries automatically to reclaim space. * * <P><em> The only reason this class is not package-private is that * there's no other public way to get at the server session context which * is associated with any given authentication context. </em> * * @author David Brownell */ final class SSLSessionImpl extends ExtendedSSLSession { /* * we only really need a single null session */ static final SSLSessionImpl nullSession = new SSLSessionImpl(); // compression methods private static final byte compression_null = 0; /* * The state of a single session, as described in section 7.1 * of the SSLv3 spec. */ private final ProtocolVersion protocolVersion; private final SessionId sessionId; private X509Certificate[] peerCerts; private byte compressionMethod; private CipherSuite cipherSuite; private SecretKey masterSecret; /* * Information not part of the SSLv3 protocol spec, but used * to support session management policies. */ private final long creationTime = System.currentTimeMillis(); private long lastUsedTime = 0; private final String host; private final int port; private SSLSessionContextImpl context; private int sessionCount; private boolean invalidated; private X509Certificate[] localCerts; private PrivateKey localPrivateKey; private String[] localSupportedSignAlgs; private String[] peerSupportedSignAlgs; // Principals for non-certificate based cipher suites private Principal peerPrincipal; private Principal localPrincipal; /* * We count session creations, eventually for statistical data but * also since counters make shorter debugging IDs than the big ones * we use in the protocol for uniqueness-over-time. */ private static volatile int counter = 0; /* * Use of session caches is globally enabled/disabled. */ private static boolean defaultRejoinable = true; /* Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); /* * Create a new non-rejoinable session, using the default (null) * cipher spec. This constructor returns a session which could * be used either by a client or by a server, as a connection is * first opened and before handshaking begins. */ private SSLSessionImpl() { this(ProtocolVersion.NONE, CipherSuite.C_NULL, null, new SessionId(false, null), null, -1); } /* * Create a new session, using a given cipher spec. This will * be rejoinable if session caching is enabled; the constructor * is intended mostly for use by serves. */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection<SignatureAndHashAlgorithm> algorithms, SecureRandom generator, String host, int port) { this(protocolVersion, cipherSuite, algorithms, new SessionId(defaultRejoinable, generator), host, port); } /* * Record a new session, using a given cipher spec and session ID. */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection<SignatureAndHashAlgorithm> algorithms, SessionId id, String host, int port) { this.protocolVersion = protocolVersion; sessionId = id; peerCerts = null; compressionMethod = compression_null; this.cipherSuite = cipherSuite; masterSecret = null; this.host = host; this.port = port; sessionCount = ++counter; localSupportedSignAlgs = SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); if (debug != null && Debug.isOn("session")) { System.out.println("%% Initialized: " + this); } } void setMasterSecret(SecretKey secret) { if (masterSecret == null) { masterSecret = secret; } else { throw new RuntimeException("setMasterSecret() error"); } } /** * Returns the master secret ... treat with extreme caution! */ SecretKey getMasterSecret() { return masterSecret; } void setPeerCertificates(X509Certificate[] peer) { if (peerCerts == null) { peerCerts = peer; } } void setLocalCertificates(X509Certificate[] local) { localCerts = local; } void setLocalPrivateKey(PrivateKey privateKey) { localPrivateKey = privateKey; } void setPeerSupportedSignatureAlgorithms( Collection<SignatureAndHashAlgorithm> algorithms) { peerSupportedSignAlgs = SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); } /** * Set the peer principal. */ void setPeerPrincipal(Principal principal) { if (peerPrincipal == null) { peerPrincipal = principal; } } /** * Set the local principal. */ void setLocalPrincipal(Principal principal) { localPrincipal = principal; } /** * Returns true iff this session may be resumed ... sessions are * usually resumable. Security policies may suggest otherwise, * for example sessions that haven't been used for a while (say, * a working day) won't be resumable, and sessions might have a * maximum lifetime in any case. */ boolean isRejoinable() { return sessionId != null && sessionId.length() != 0 && !invalidated && isLocalAuthenticationValid(); } public synchronized boolean isValid() { return isRejoinable(); } /** * Check if the authentication used when establishing this session * is still valid. Returns true if no authentication was used */ boolean isLocalAuthenticationValid() { if (localPrivateKey != null) { try { // if the private key is no longer valid, getAlgorithm() // should throw an exception // (e.g. Smartcard has been removed from the reader) localPrivateKey.getAlgorithm(); } catch (Exception e) { invalidate(); return false; } } return true; } /** * Returns the ID for this session. The ID is fixed for the * duration of the session; neither it, nor its value, changes. */ public byte[] getId() { return sessionId.getId(); } /** * For server sessions, this returns the set of sessions which * are currently valid in this process. For client sessions, * this returns null. */ public SSLSessionContext getSessionContext() { /* * An interim security policy until we can do something * more specific in 1.2. Only allow trusted code (code which * can set system properties) to get an * SSLSessionContext. This is to limit the ability of code to * look up specific sessions or enumerate over them. Otherwise, * code can only get session objects from successful SSL * connections which implies that they must have had permission * to make the network connection in the first place. */ SecurityManager sm; if ((sm = System.getSecurityManager()) != null) { sm.checkPermission(new SSLPermission("getSSLSessionContext")); } return context; } SessionId getSessionId() { return sessionId; } /** * Returns the cipher spec in use on this session */ CipherSuite getSuite() { return cipherSuite; } /** * Resets the cipher spec in use on this session */ void setSuite(CipherSuite suite) { cipherSuite = suite; if (debug != null && Debug.isOn("session")) { System.out.println("%% Negotiating: " + this); } } /** * Returns the name of the cipher suite in use on this session */ public String getCipherSuite() { return getSuite().name; } ProtocolVersion getProtocolVersion() { return protocolVersion; } /** * Returns the standard name of the protocol in use on this session */ public String getProtocol() { return getProtocolVersion().name; } /** * Returns the compression technique used in this session */ byte getCompression() { return compressionMethod; } /** * Returns the hashcode for this session */ public int hashCode() { return sessionId.hashCode(); } /** * Returns true if sessions have same ids, false otherwise. */ public boolean equals(Object obj) { if (obj == this) { return true; } if (obj instanceof SSLSessionImpl) { SSLSessionImpl sess = (SSLSessionImpl) obj; return (sessionId != null) && (sessionId.equals( sess.getSessionId())); } return false; } /** * Return the cert chain presented by the peer in the * java.security.cert format. * Note: This method can be used only when using certificate-based * cipher suites; using it with non-certificate-based cipher suites, * such as Kerberos, will throw an SSLPeerUnverifiedException. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { // // clone to preserve integrity of session ... caller can't // change record of peer identity even by accident, much // less do it intentionally. // if ((cipherSuite.keyExchange == K_KRB5) || (cipherSuite.keyExchange == K_KRB5_EXPORT)) { throw new SSLPeerUnverifiedException("no certificates expected" + " for Kerberos cipher suites"); } if (peerCerts == null) { throw new SSLPeerUnverifiedException("peer not authenticated"); } // Certs are immutable objects, therefore we don't clone them. // But do need to clone the array, so that nothing is inserted // into peerCerts. return (java.security.cert.Certificate[])peerCerts.clone(); } /** * Return the cert chain presented to the peer in the * java.security.cert format. * Note: This method is useful only when using certificate-based * cipher suites. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public java.security.cert.Certificate[] getLocalCertificates() { // // clone to preserve integrity of session ... caller can't // change record of peer identity even by accident, much // less do it intentionally. return (localCerts == null ? null : (java.security.cert.Certificate[])localCerts.clone()); } /** * Return the cert chain presented by the peer in the * javax.security.cert format. * Note: This method can be used only when using certificate-based * cipher suites; using it with non-certificate-based cipher suites, * such as Kerberos, will throw an SSLPeerUnverifiedException. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public javax.security.cert.X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException { // // clone to preserve integrity of session ... caller can't // change record of peer identity even by accident, much // less do it intentionally. // if ((cipherSuite.keyExchange == K_KRB5) || (cipherSuite.keyExchange == K_KRB5_EXPORT)) { throw new SSLPeerUnverifiedException("no certificates expected" + " for Kerberos cipher suites"); } if (peerCerts == null) { throw new SSLPeerUnverifiedException("peer not authenticated"); } javax.security.cert.X509Certificate[] certs; certs = new javax.security.cert.X509Certificate[peerCerts.length]; for (int i = 0; i < peerCerts.length; i++) { byte[] der = null; try { der = peerCerts[i].getEncoded(); certs[i] = javax.security.cert.X509Certificate.getInstance(der); } catch (CertificateEncodingException e) { throw new SSLPeerUnverifiedException(e.getMessage()); } catch (javax.security.cert.CertificateException e) { throw new SSLPeerUnverifiedException(e.getMessage()); } } return certs; } /** * Return the cert chain presented by the peer. * Note: This method can be used only when using certificate-based * cipher suites; using it with non-certificate-based cipher suites, * such as Kerberos, will throw an SSLPeerUnverifiedException. * * @return array of peer X.509 certs, with the peer's own cert * first in the chain, and with the "root" CA last. */ public X509Certificate[] getCertificateChain() throws SSLPeerUnverifiedException { /* * clone to preserve integrity of session ... caller can't * change record of peer identity even by accident, much * less do it intentionally. */ if ((cipherSuite.keyExchange == K_KRB5) || (cipherSuite.keyExchange == K_KRB5_EXPORT)) { throw new SSLPeerUnverifiedException("no certificates expected" + " for Kerberos cipher suites"); } if (peerCerts != null) { return peerCerts.clone(); } else { throw new SSLPeerUnverifiedException("peer not authenticated"); } } /** * Returns the identity of the peer which was established as part of * defining the session. * * @return the peer's principal. Returns an X500Principal of the * end-entity certificate for X509-based cipher suites, and * Principal for Kerberos cipher suites. *