File: README.md

package info (click to toggle)
libokhttp-java 3.13.1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,352 kB
  • sloc: java: 60,087; xml: 1,869; sh: 41; makefile: 12
file content (246 lines) | stat: -rw-r--r-- 9,673 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
OkHttp TLS
==========

Approachable APIs for using TLS.

A [`HeldCertificate`][held_certificate] is a certificate and its private key. Use the
[builder][held_certificate_builder] to create a self-signed certificate that a test server can use
for HTTPS:

```java
String localhost = InetAddress.getByName("localhost").getCanonicalHostName();
HeldCertificate localhostCertificate = new HeldCertificate.Builder()
    .addSubjectAlternativeName(localhost)
    .build();
```

[`HandshakeCertificates`][handshake_certificates] keeps the certificates for a TLS handshake.
Use its [builder][handshake_certificates_builder] to define which certificates the HTTPS server
returns to its clients. The returned instance can create an `SSLSocketFactory` that implements this
policy:

```java
HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder()
    .heldCertificate(localhostCertificate)
    .build();
MockWebServer server = new MockWebServer();
server.useHttps(serverCertificates.sslSocketFactory(), false);
```

`HandshakeCertificates` also works for clients where its job is to define which root certificates
to trust. In this simplified example we trust the server's self-signed certificate:

```java
HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
    .addTrustedCertificate(localhostCertificate.certificate())
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
    .build();
```

With a server that holds a certificate and a client that trusts it we have enough for an HTTPS
handshake. The best part of this example is that we don't need to make our test code insecure with a
a fake `HostnameVerifier` or `X509TrustManager`.

Certificate Authorities
-----------------------

The above example uses a self-signed certificate. This is convenient for testing but not
representative of real-world HTTPS deployment. To get closer to that we can use `HeldCertificate`
to generate a trusted root certificate, an intermediate certificate, and a server certificate.
We use `certificateAuthority(int)` to create certificates that can sign other certificates. The
int specifies how many intermediate certificates are allowed beneath it in the chain.

```java
HeldCertificate rootCertificate = new HeldCertificate.Builder()
    .certificateAuthority(1)
    .build();

HeldCertificate intermediateCertificate = new HeldCertificate.Builder()
    .certificateAuthority(0)
    .signedBy(rootCertificate)
    .build();

String localhost = InetAddress.getByName("localhost").getCanonicalHostName();
HeldCertificate serverCertificate = new HeldCertificate.Builder()
    .addSubjectAlternativeName(localhost)
    .signedBy(intermediateCertificate)
    .build();
```

To serve this configuration the server needs to provide its clients with a chain of certificates
starting with its own and including everything up-to but not including the root. We don't need to
include root certificates because the client already has them.

```java
HandshakeCertificates serverHandshakeCertificates = new HandshakeCertificates.Builder()
    .heldCertificate(serverCertificate, intermediateCertificate.certificate())
    .build();
```

The client only needs to know the trusted root certificate. It checks the server's certificate by
validating the signatures within the chain.

```java
HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
    .addTrustedCertificate(rootCertificate.certificate())
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
    .build();
```

Client Authentication
---------------------

The above scenario is representative of most TLS set ups: the client uses certificates to validate
the identity of a server. The converse is also possible. Here we create a server that authenticates
a client and a client that authenticates a server.

```java
// Create the root for client and server to trust. We could also use different roots for each!
HeldCertificate rootCertificate = new HeldCertificate.Builder()
    .certificateAuthority(0)
    .build();

// Create a server certificate and a server that uses it.
HeldCertificate serverCertificate = new HeldCertificate.Builder()
    .commonName("ingen")
    .addSubjectAlternativeName(server.getHostName())
    .signedBy(rootCertificate)
    .build();
HandshakeCertificates serverCertificates = new HandshakeCertificates.Builder()
    .addTrustedCertificate(rootCertificate.certificate())
    .heldCertificate(serverCertificate)
    .build();
MockWebServer server = new MockWebServer();
server.useHttps(serverCertificates.sslSocketFactory(), false);
server.requestClientAuth();
server.enqueue(new MockResponse());

// Create a client certificate and a client that uses it.
HeldCertificate clientCertificate = new HeldCertificate.Builder()
    .commonName("ianmalcolm")
    .signedBy(rootCertificate)
    .build();
HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
    .addTrustedCertificate(rootCertificate.certificate())
    .heldCertificate(clientCertificate)
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
    .build();

// Connect 'em all together. Certificates are exchanged in the handshake.
Call call = client.newCall(new Request.Builder()
    .url(server.url("/"))
    .build());
Response response = call.execute();
System.out.println(response.handshake().peerPrincipal());
RecordedRequest recordedRequest = server.takeRequest();
System.out.println(recordedRequest.getHandshake().peerPrincipal());
```

This handshake is successful because each party has prearranged to trust the root certificate that
signs the other party's chain.

Well-Known Certificate Authorities
----------------------------------

In these examples we've prearranged which root certificates to trust. But for regular HTTPS on the
Internet this set of trusted root certificates is usually provided by default by the host platform.
Such a set typically includes many root certificates from well-known certificate authorities like
Entrust and Verisign.

This is the behavior you'll get with your OkHttpClient if you don't specifically configure
`HandshakeCertificates`. Or you can do it explicitly with `addPlatformTrustedCertificates()`:

```java
HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
    .addPlatformTrustedCertificates()
    .build();
OkHttpClient client = new OkHttpClient.Builder()
    .sslSocketFactory(clientCertificates.sslSocketFactory(), clientCertificates.trustManager())
    .build();
```

PEM files
---------

You can encode a `HeldCertificate` in PEM format:

```java
HeldCertificate heldCertificate = ...
System.out.println(heldCertificate.certificatePem())
```

```
-----BEGIN CERTIFICATE-----
MIIBSjCB8aADAgECAgEBMAoGCCqGSM49BAMCMC8xLTArBgNVBAMTJDJiYWY3NzVl
LWE4MzUtNDM5ZS1hYWE2LTgzNmNiNDlmMGM3MTAeFw0xODA3MTMxMjA0MzJaFw0x
ODA3MTQxMjA0MzJaMC8xLTArBgNVBAMTJDJiYWY3NzVlLWE4MzUtNDM5ZS1hYWE2
LTgzNmNiNDlmMGM3MTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDmlOiZ3dxA2
zw1KwqGNsKVUZbkUVj5cxV1jDbSTvTlOjSj6LR0Ovys9RFdrjcbbMLWvSvMQgHch
k8Q50c6Kb34wCgYIKoZIzj0EAwIDSAAwRQIhAJkXiCbIR3zxuH5SQR5PEAPJ+ntg
msOSMaAKwAePESf+AiBlxbEu6YpHt1ZJoAhMAv6raYnwSp/A94eJGlJynQ0igQ==
-----END CERTIFICATE-----
```

You can also do so with the private key. Be careful with these!

```java
HeldCertificate heldCertificate = ...
System.out.println(heldCertificate.privateKeyPkcs8Pem())
```

```
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgQbYDQiewSnregm9e
IjXEHQgc6w3ELHdnH1houEUom9CgCgYIKoZIzj0DAQehRANCAAQ5pTomd3cQNs8N
SsKhjbClVGW5FFY+XMVdYw20k705To0o+i0dDr8rPURXa43G2zC1r0rzEIB3IZPE
OdHOim9+
-----END PRIVATE KEY-----
```

Recommendations
---------------

Typically servers need a held certificate plus a chain of intermediates. Servers only need the
private key for their own certificate. The chain served by a server doesn't need the root
certificate.

The trusted roots don't need to be the same for client and server when using client authentication.
Clients might rely on the platform certificates and servers might use a private
organization-specific certificate authority.

By default `HeldCertificate` instances expire after 24 hours. Use `duration()` to adjust.

By default server certificates need to identify which hostnames they're trusted for. You may add as
many as necessary with `addSubjectAlternativeName()`. This mechanism also supports a very limited
form of wildcards `*.example.com` where the `*` must be first and doesn't match nested subdomains.

By default certificates use fast and secure 256-bit ECDSA keys. For interoperability with very old
clients use `HeldCertificate.Builder.rsa2048()`.

Download
--------

Get via Maven:
```xml
<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp-tls</artifactId>
  <version>(insert latest version)</version>
</dependency>
```

or via Gradle
```groovy
implementation 'com.squareup.okhttp3:okhttp-tls:(insert latest version)'
```

 [held_certificate]: http://square.github.io/okhttp/3.x/okhttp-tls/okhttp3/tls/HeldCertificate.html
 [held_certificate_builder]: http://square.github.io/okhttp/3.x/okhttp-tls/okhttp3/tls/HeldCertificate.Builder.html
 [handshake_certificates]: http://square.github.io/okhttp/3.x/okhttp-tls/okhttp3/tls/HandshakeCertificates.html
 [handshake_certificates_builder]: http://square.github.io/okhttp/3.x/okhttp-tls/okhttp3/tls/HandshakeCertificates.Builder.html