• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Square, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.squareup.okhttp;
17 
18 import java.security.GeneralSecurityException;
19 import java.util.Set;
20 import javax.net.ssl.SSLPeerUnverifiedException;
21 import com.squareup.okhttp.internal.HeldCertificate;
22 import okio.ByteString;
23 import org.junit.Test;
24 
25 import static com.squareup.okhttp.TestUtil.setOf;
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.fail;
31 
32 public final class CertificatePinnerTest {
33   static HeldCertificate certA1;
34   static String certA1Pin;
35   static ByteString certA1PinBase64;
36 
37   static HeldCertificate certB1;
38   static String certB1Pin;
39   static ByteString certB1PinBase64;
40 
41   static HeldCertificate certC1;
42   static String certC1Pin;
43 
44   static {
45     try {
46       certA1 = new HeldCertificate.Builder()
47           .serialNumber("100")
48           .build();
49       certA1Pin = CertificatePinner.pin(certA1.certificate);
50       certA1PinBase64 = pinToBase64(certA1Pin);
51 
52       certB1 = new HeldCertificate.Builder()
53           .serialNumber("200")
54           .build();
55       certB1Pin = CertificatePinner.pin(certB1.certificate);
56       certB1PinBase64 = pinToBase64(certB1Pin);
57 
58       certC1 = new HeldCertificate.Builder()
59           .serialNumber("300")
60           .build();
61       certC1Pin = CertificatePinner.pin(certC1.certificate);
62     } catch (GeneralSecurityException e) {
63       throw new AssertionError(e);
64     }
65   }
66 
pinToBase64(String pin)67   static ByteString pinToBase64(String pin) {
68     return ByteString.decodeBase64(pin.substring("sha1/".length()));
69   }
70 
malformedPin()71   @Test public void malformedPin() throws Exception {
72     CertificatePinner.Builder builder = new CertificatePinner.Builder();
73     try {
74       builder.add("example.com", "md5/DmxUShsZuNiqPQsX2Oi9uv2sCnw=");
75       fail();
76     } catch (IllegalArgumentException expected) {
77     }
78   }
79 
malformedBase64()80   @Test public void malformedBase64() throws Exception {
81     CertificatePinner.Builder builder = new CertificatePinner.Builder();
82     try {
83       builder.add("example.com", "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw*");
84       fail();
85     } catch (IllegalArgumentException expected) {
86     }
87   }
88 
89   /** Multiple certificates generated from the same keypair have the same pin. */
sameKeypairSamePin()90   @Test public void sameKeypairSamePin() throws Exception {
91     HeldCertificate heldCertificateA2 = new HeldCertificate.Builder()
92         .keyPair(certA1.keyPair)
93         .serialNumber("101")
94         .build();
95     String keypairACertificate2Pin = CertificatePinner.pin(heldCertificateA2.certificate);
96 
97     HeldCertificate heldCertificateB2 = new HeldCertificate.Builder()
98         .keyPair(certB1.keyPair)
99         .serialNumber("201")
100         .build();
101     String keypairBCertificate2Pin = CertificatePinner.pin(heldCertificateB2.certificate);
102 
103     assertTrue(certA1Pin.equals(keypairACertificate2Pin));
104     assertTrue(certB1Pin.equals(keypairBCertificate2Pin));
105     assertFalse(certA1Pin.equals(certB1Pin));
106   }
107 
successfulCheck()108   @Test public void successfulCheck() throws Exception {
109     CertificatePinner certificatePinner = new CertificatePinner.Builder()
110         .add("example.com", certA1Pin)
111         .build();
112 
113     certificatePinner.check("example.com", certA1.certificate);
114   }
115 
successfulMatchAcceptsAnyMatchingCertificate()116   @Test public void successfulMatchAcceptsAnyMatchingCertificate() throws Exception {
117     CertificatePinner certificatePinner = new CertificatePinner.Builder()
118         .add("example.com", certB1Pin)
119         .build();
120 
121     certificatePinner.check("example.com", certA1.certificate, certB1.certificate);
122   }
123 
unsuccessfulCheck()124   @Test public void unsuccessfulCheck() throws Exception {
125     CertificatePinner certificatePinner = new CertificatePinner.Builder()
126         .add("example.com", certA1Pin)
127         .build();
128 
129     try {
130       certificatePinner.check("example.com", certB1.certificate);
131       fail();
132     } catch (SSLPeerUnverifiedException expected) {
133     }
134   }
135 
multipleCertificatesForOneHostname()136   @Test public void multipleCertificatesForOneHostname() throws Exception {
137     CertificatePinner certificatePinner = new CertificatePinner.Builder()
138         .add("example.com", certA1Pin, certB1Pin)
139         .build();
140 
141     certificatePinner.check("example.com", certA1.certificate);
142     certificatePinner.check("example.com", certB1.certificate);
143   }
144 
multipleHostnamesForOneCertificate()145   @Test public void multipleHostnamesForOneCertificate() throws Exception {
146     CertificatePinner certificatePinner = new CertificatePinner.Builder()
147         .add("example.com", certA1Pin)
148         .add("www.example.com", certA1Pin)
149         .build();
150 
151     certificatePinner.check("example.com", certA1.certificate);
152     certificatePinner.check("www.example.com", certA1.certificate);
153   }
154 
absentHostnameMatches()155   @Test public void absentHostnameMatches() throws Exception {
156     CertificatePinner certificatePinner = new CertificatePinner.Builder().build();
157     certificatePinner.check("example.com", certA1.certificate);
158   }
159 
successfulCheckForWildcardHostname()160   @Test public void successfulCheckForWildcardHostname() throws Exception {
161     CertificatePinner certificatePinner = new CertificatePinner.Builder()
162         .add("*.example.com", certA1Pin)
163         .build();
164 
165     certificatePinner.check("a.example.com", certA1.certificate);
166   }
167 
successfulMatchAcceptsAnyMatchingCertificateForWildcardHostname()168   @Test public void successfulMatchAcceptsAnyMatchingCertificateForWildcardHostname() throws Exception {
169     CertificatePinner certificatePinner = new CertificatePinner.Builder()
170         .add("*.example.com", certB1Pin)
171         .build();
172 
173     certificatePinner.check("a.example.com", certA1.certificate, certB1.certificate);
174   }
175 
unsuccessfulCheckForWildcardHostname()176   @Test public void unsuccessfulCheckForWildcardHostname() throws Exception {
177     CertificatePinner certificatePinner = new CertificatePinner.Builder()
178         .add("*.example.com", certA1Pin)
179         .build();
180 
181     try {
182       certificatePinner.check("a.example.com", certB1.certificate);
183       fail();
184     } catch (SSLPeerUnverifiedException expected) {
185     }
186   }
187 
multipleCertificatesForOneWildcardHostname()188   @Test public void multipleCertificatesForOneWildcardHostname() throws Exception {
189     CertificatePinner certificatePinner = new CertificatePinner.Builder()
190         .add("*.example.com", certA1Pin, certB1Pin)
191         .build();
192 
193     certificatePinner.check("a.example.com", certA1.certificate);
194     certificatePinner.check("a.example.com", certB1.certificate);
195   }
196 
successfulCheckForOneHostnameWithWildcardAndDirectCertificate()197   @Test public void successfulCheckForOneHostnameWithWildcardAndDirectCertificate() throws Exception {
198     CertificatePinner certificatePinner = new CertificatePinner.Builder()
199         .add("*.example.com", certA1Pin)
200         .add("a.example.com", certB1Pin)
201         .build();
202 
203     certificatePinner.check("a.example.com", certA1.certificate);
204     certificatePinner.check("a.example.com", certB1.certificate);
205   }
206 
unsuccessfulCheckForOneHostnameWithWildcardAndDirectCertificate()207   @Test public void unsuccessfulCheckForOneHostnameWithWildcardAndDirectCertificate() throws Exception {
208     CertificatePinner certificatePinner = new CertificatePinner.Builder()
209         .add("*.example.com", certA1Pin)
210         .add("a.example.com", certB1Pin)
211         .build();
212 
213     try {
214       certificatePinner.check("a.example.com", certC1.certificate);
215       fail();
216     } catch (SSLPeerUnverifiedException expected) {
217     }
218   }
219 
successfulFindMatchingPins()220   @Test public void successfulFindMatchingPins() {
221     CertificatePinner certificatePinner = new CertificatePinner.Builder()
222         .add("first.com", certA1Pin, certB1Pin)
223         .add("second.com", certC1Pin)
224         .build();
225 
226     Set<ByteString> expectedPins = setOf(certA1PinBase64, certB1PinBase64);
227     Set<ByteString> matchedPins = certificatePinner.findMatchingPins("first.com");
228 
229     assertEquals(expectedPins, matchedPins);
230   }
231 
successfulFindMatchingPinsForWildcardAndDirectCertificates()232   @Test public void successfulFindMatchingPinsForWildcardAndDirectCertificates() {
233     CertificatePinner certificatePinner = new CertificatePinner.Builder()
234         .add("*.example.com", certA1Pin)
235         .add("a.example.com", certB1Pin)
236         .add("b.example.com", certC1Pin)
237         .build();
238 
239     Set<ByteString> expectedPins = setOf(certA1PinBase64, certB1PinBase64);
240     Set<ByteString> matchedPins = certificatePinner.findMatchingPins("a.example.com");
241 
242     assertEquals(expectedPins, matchedPins);
243   }
244 
wildcardHostnameShouldNotMatchThroughDot()245   @Test public void wildcardHostnameShouldNotMatchThroughDot() throws Exception {
246     CertificatePinner certificatePinner = new CertificatePinner.Builder()
247         .add("*.example.com", certA1Pin)
248         .build();
249 
250     assertNull(certificatePinner.findMatchingPins("example.com"));
251     assertNull(certificatePinner.findMatchingPins("a.b.example.com"));
252   }
253 }
254