13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/* 23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Copyright (C) 2013 Square, Inc. 33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * you may not use this file except in compliance with the License. 63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * You may obtain a copy of the License at 73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * http://www.apache.org/licenses/LICENSE-2.0 93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Unless required by applicable law or agreed to in writing, software 113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * See the License for the specific language governing permissions and 143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * limitations under the License. 153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage com.squareup.okhttp; 183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.Util; 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.security.Principal; 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.security.cert.Certificate; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.security.cert.X509Certificate; 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Collections; 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.List; 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport javax.net.ssl.SSLPeerUnverifiedException; 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport javax.net.ssl.SSLSession; 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/** 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * A record of a TLS handshake. For HTTPS clients, the client is <i>local</i> 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * and the remote server is its <i>peer</i>. 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>This value object describes a completed handshake. Use {@link 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * javax.net.ssl.SSLSocketFactory} to set policy for new handshakes. 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic final class Handshake { 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final String cipherSuite; 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final List<Certificate> peerCertificates; 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final List<Certificate> localCertificates; 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private Handshake( 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String cipherSuite, List<Certificate> peerCertificates, List<Certificate> localCertificates) { 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.cipherSuite = cipherSuite; 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.peerCertificates = peerCertificates; 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.localCertificates = localCertificates; 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public static Handshake get(SSLSession session) { 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String cipherSuite = session.getCipherSuite(); 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (cipherSuite == null) throw new IllegalStateException("cipherSuite == null"); 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Certificate[] peerCertificates; 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller try { 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller peerCertificates = session.getPeerCertificates(); 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } catch (SSLPeerUnverifiedException ignored) { 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller peerCertificates = null; 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Certificate> peerCertificatesList = peerCertificates != null 583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? Util.immutableList(peerCertificates) 593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : Collections.<Certificate>emptyList(); 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Certificate[] localCertificates = session.getLocalCertificates(); 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller List<Certificate> localCertificatesList = localCertificates != null 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? Util.immutableList(localCertificates) 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : Collections.<Certificate>emptyList(); 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new Handshake(cipherSuite, peerCertificatesList, localCertificatesList); 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public static Handshake get( 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String cipherSuite, List<Certificate> peerCertificates, List<Certificate> localCertificates) { 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (cipherSuite == null) throw new IllegalArgumentException("cipherSuite == null"); 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new Handshake(cipherSuite, Util.immutableList(peerCertificates), 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Util.immutableList(localCertificates)); 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns a cipher suite name like "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA". */ 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public String cipherSuite() { 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return cipherSuite; 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns a possibly-empty list of certificates that identify the remote peer. */ 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public List<Certificate> peerCertificates() { 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return peerCertificates; 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns the remote peer's principle, or null if that peer is anonymous. */ 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Principal peerPrincipal() { 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return !peerCertificates.isEmpty() 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? ((X509Certificate) peerCertificates.get(0)).getSubjectX500Principal() 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : null; 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns a possibly-empty list of certificates that identify this peer. */ 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public List<Certificate> localCertificates() { 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return localCertificates; 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** Returns the local principle, or null if this peer is anonymous. */ 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public Principal localPrincipal() { 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return !localCertificates.isEmpty() 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller ? ((X509Certificate) localCertificates.get(0)).getSubjectX500Principal() 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller : null; 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public boolean equals(Object other) { 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!(other instanceof Handshake)) return false; 1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller Handshake that = (Handshake) other; 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return cipherSuite.equals(that.cipherSuite) 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller && peerCertificates.equals(that.peerCertificates) 1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller && localCertificates.equals(that.localCertificates); 1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller @Override public int hashCode() { 1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int result = 17; 1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result = 31 * result + cipherSuite.hashCode(); 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result = 31 * result + peerCertificates.hashCode(); 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller result = 31 * result + localCertificates.hashCode(); 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return result; 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 121