|
1
|
# SSL/TLS Server Mode |
|
2
|
|
|
3
|
## History |
|
4
|
|
|
5
|
Fossil has supported [client-side SSL/TLS][0] since [2010][1]. This means |
|
6
|
that commands like "[fossil sync](/help/sync)" could use SSL/TLS when |
|
7
|
contacting a server. But on the server side, commands like |
|
8
|
"[fossil server](/help/server)" operated in clear-text only. To implement |
|
9
|
an encrypted server, you had to put Fossil behind a web server or reverse |
|
10
|
proxy that handled the SSL/TLS decryption/encryption and passed cleartext |
|
11
|
down to Fossil. |
|
12
|
|
|
13
|
[0]: ./ssl.wiki |
|
14
|
[1]: /timeline?c=b05cb4a0e15d0712&y=ci&n=13 |
|
15
|
|
|
16
|
Beginning in [late December 2021](/timeline?c=f6263bb64195b07f&y=a&n=13), |
|
17
|
Fossil servers are now able to converse directly over TLS. Commands like |
|
18
|
|
|
19
|
* "[fossil server](/help/server)" |
|
20
|
* "[fossil ui](/help/ui)", and |
|
21
|
* "[fossil http](/help/http)" |
|
22
|
|
|
23
|
may now handle the encryption natively when suitably configured, without |
|
24
|
requiring a third-party proxy layer. |
|
25
|
|
|
26
|
## <a id="usage"></a>Usage |
|
27
|
|
|
28
|
To put any of the Fossil server commands into SSL/TLS mode, simply |
|
29
|
add the "`--cert`" command-line option: |
|
30
|
|
|
31
|
fossil ui --cert unsafe-builtin |
|
32
|
|
|
33
|
Here, we are passing the magic name "unsafe-builtin" to cause Fossil to |
|
34
|
use a [hard-coded self-signed cert][hcssc] rather than one obtained from |
|
35
|
a recognized [Certificate Authority][CA], or "CA". |
|
36
|
|
|
37
|
As the name implies, this self-signed cert is _not secure_ and should |
|
38
|
only be used for testing. Your web browser is likely to complain |
|
39
|
bitterly about it and will refuse to display the pages using the |
|
40
|
"unsafe-builtin" cert until you placate it. The complexity of the |
|
41
|
ceremony demanded depends on how paranoid your browser’s creators have |
|
42
|
decided to be. It may require as little as clicking a single big "I know |
|
43
|
the risks" type of button, or it may require a sequence be several |
|
44
|
clicks designed to discourage the “yes, yes, just let me do the thing” |
|
45
|
crowd lest they run themselves into trouble by disregarding well-meant |
|
46
|
warnings. |
|
47
|
|
|
48
|
Our purpose here is to show you an alternate path that will avoid the |
|
49
|
issue entirely, not weigh in on which browser handles self-signed |
|
50
|
certificates best. |
|
51
|
|
|
52
|
[CA]: https://en.wikipedia.org/wiki/Certificate_authority |
|
53
|
[hcssc]: /info/c2a7b14c3f541edb96?ln=89-116 |
|
54
|
|
|
55
|
## <a id="about"></a>About Certs |
|
56
|
|
|
57
|
The X.509 certificate system used by browsers to secure TLS connections |
|
58
|
is based on asymmetric public-key cryptography. The methods for |
|
59
|
obtaining one vary widely, with a resulting tradeoff we may summarize as |
|
60
|
trustworthiness versus convenience, the latter characteristic falling as |
|
61
|
the former rises.(^No strict correlation exists. CAs have invented |
|
62
|
highly inconvenient certification schemes that offer little additional |
|
63
|
real-world trustworthiness. Extreme cases along this axis may be fairly |
|
64
|
characterized as [security theater][st]. We focus in this document on |
|
65
|
well-balanced trade-offs between decreasing convenience and useful |
|
66
|
levels of trustworthiness gained thereby.) |
|
67
|
|
|
68
|
The self-signed method demonstrated above offers approximately zero |
|
69
|
trustworthiness, though not zero _value_ since it does still provide |
|
70
|
connection encryption. |
|
71
|
|
|
72
|
More trustworthy methods are necessarily less convenient. One such is to |
|
73
|
send your public key and the name of the domain you want to protect to a |
|
74
|
recognized CA, which then performs one or more tests to convince itself |
|
75
|
that the requester is in control of that domain. If the CA’s tests all |
|
76
|
pass, it produces an X.509 certificate bound to that domain, which |
|
77
|
includes assorted other information under the CA’s digital signature |
|
78
|
attesting to the validity of the document’s contents. The result is sent |
|
79
|
back to the requester, which may then use it to transitively attest to |
|
80
|
these tests’ success: presuming one cannot fake the type of signature |
|
81
|
used, the document must have been signed by the trusted, recognized CA. |
|
82
|
|
|
83
|
There is one element of the assorted information included with a |
|
84
|
certificate that is neither supplied by the requester nor rubber-stamped |
|
85
|
on it in passing by the CA. It also generates a one-time key pair and |
|
86
|
stores the public half in the certificate. The cryptosystem this keypair |
|
87
|
is intended to work with varies both by the CA and by time, as older |
|
88
|
systems become obsolete. Details aside, the CA then puts this matching |
|
89
|
private half of the key in a separate file, often encrypted under a |
|
90
|
separate cryptosystem for security. |
|
91
|
|
|
92
|
SSL/TLS servers need both resulting halves to make these attestations, |
|
93
|
but they send only the public half to the client when establishing the |
|
94
|
connection. The client then makes its own checks to determine whether it |
|
95
|
trusts the attestations being made. |
|
96
|
|
|
97
|
A properly written and administered server never releases the private |
|
98
|
key to anyone. Ideally, it goes directly from the CA to the requesting |
|
99
|
server and never moves from there; then when it expires, the server |
|
100
|
deletes it permanently. |
|
101
|
|
|
102
|
[st]: https://en.wikipedia.org/wiki/Security_theater |
|
103
|
|
|
104
|
## <a id="startup"></a>How To Tell Fossil About Your Cert And Private Key |
|
105
|
|
|
106
|
As we saw [above](#usage), |
|
107
|
if you do not have your own cert and private key, you can ask Fossil |
|
108
|
to use "unsafe-builtin", which is a self-signed cert that is built into |
|
109
|
Fossil. This is wildly insecure, since the private key is not really private; |
|
110
|
it is [in plain sight][hcssc] in the Fossil |
|
111
|
source tree for anybody to read. <b>Never add the private key that is |
|
112
|
built into Fossil to your OS's trust store</b> as doing so will severely |
|
113
|
compromise your computer.[^ssattack] This built-in cert is only useful for testing. |
|
114
|
If you want actual security, you will need to come up with your own private |
|
115
|
key and cert. |
|
116
|
|
|
117
|
Fossil wants to read certs and public keys in the |
|
118
|
[PEM format](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). |
|
119
|
PEM is a pure ASCII text format. The private key consists of text |
|
120
|
like this: |
|
121
|
|
|
122
|
-----BEGIN PRIVATE KEY----- |
|
123
|
*base-64 encoding of the private key* |
|
124
|
-----END PRIVATE KEY----- |
|
125
|
|
|
126
|
Similarly, a PEM-encoded cert will look like this: |
|
127
|
|
|
128
|
-----BEGIN CERTIFICATE----- |
|
129
|
*base-64 encoding of the certificate* |
|
130
|
-----END CERTIFICATE----- |
|
131
|
|
|
132
|
In both formats, text outside of the delimiters is ignored. That means |
|
133
|
that if you have a PEM-formatted private key and a separate PEM-formatted |
|
134
|
certificate, you can concatenate the two into a single file, and the |
|
135
|
individual components will still be easily accessible. |
|
136
|
|
|
137
|
### <a id="cat"></a>Separate or Concatenated? |
|
138
|
|
|
139
|
Given a single concatenated file that holds both your private key and your |
|
140
|
cert, you can hand it off to the "[fossil server](/help/server)" |
|
141
|
command using the `--cert` option, like this: |
|
142
|
|
|
143
|
fossil server --port 443 --cert mycert.pem /home/www/myproject.fossil |
|
144
|
|
|
145
|
The command above is sufficient to run a fully-encrypted web site for |
|
146
|
the "myproject.fossil" Fossil repository. This command must be run as |
|
147
|
root, since it wants to listen on TCP port 443, and only root processes are |
|
148
|
allowed to do that. This is safe, however, since before reading any |
|
149
|
information off of the wire, Fossil will [put itself inside a chroot |
|
150
|
jail](./chroot.md) at `/home/www` and drop all root privileges. |
|
151
|
|
|
152
|
This method of combining your cert and private key into a single big PEM |
|
153
|
file carries risks, one of which is that the system administrator must |
|
154
|
make both halves readable by the user running the Fossil server. Given |
|
155
|
the chroot jail feature, a more secure scheme separates the halves so |
|
156
|
that only root can read the private half, which then means that when |
|
157
|
Fossil drops its root privileges, it becomes unable to access the |
|
158
|
private key on disk. Fossil’s `server` feature includes the `--pkey` |
|
159
|
option to allow for that use case: |
|
160
|
|
|
161
|
fossil server --port 443 --cert fullchain.pem --pkey privkey.pem /home/www/myproject.fossil |
|
162
|
|
|
163
|
[^ssattack]: ^How, you ask? Because the keys are known, they can be used |
|
164
|
to provide signed certificates for **any** other domain. One foolish |
|
165
|
enough to tell their OS’s TLS mechanisms to trust the signing |
|
166
|
certificate is implicitly handing over all TLS encryption controls |
|
167
|
to any attacker that knows they did this. Don’t do it. |
|
168
|
|
|
169
|
### <a id="chain"></a>Chains and Links |
|
170
|
|
|
171
|
The file name “`fullchain.pem`” used above is a reference to a term of |
|
172
|
art within this world of TLS protocols and their associated X.509 |
|
173
|
certificates. Within the simplistic scheme originally envisioned by the |
|
174
|
creators of SSL — the predecessor to TLS — we were all expected to agree |
|
175
|
on a single set of CA root authorities, and we would all agree to get |
|
176
|
our certificates from one of them. The real world is more complicated: |
|
177
|
|
|
178
|
* The closest we have to universal acceptance of CAs is via the |
|
179
|
[CA/Browser Forum][CAB], and even within its select membership there |
|
180
|
is continual argument over which roots are trustworthy. (Hashing |
|
181
|
that out is arguably this group’s key purpose.) |
|
182
|
|
|
183
|
* CAB’s decision regarding trustworthiness may not match that of any |
|
184
|
given system’s administrator. There are solid, defensible reasons to |
|
185
|
prune back the stock CA root set included with your browser, then to |
|
186
|
augment it with ones CAB _doesn’t_ trust. |
|
187
|
|
|
188
|
* TLS isn’t limited to use between web browsers and public Internet |
|
189
|
sites. Several common use cases preclude use of the process CAB |
|
190
|
envisions, with servers able to contact Internet-based CA roots as |
|
191
|
part of proving their identity. Different use cases demand different |
|
192
|
CA root authority stores. |
|
193
|
|
|
194
|
The most common of these divergent cases are servers behind strict |
|
195
|
firewalls and edge devices that never interact with the public |
|
196
|
Internet. This class ranges from cheap home IoT devices to the |
|
197
|
internal equipment managed by IT for a massive global corporation. |
|
198
|
|
|
199
|
Your private Fossil server is liable to fall into that last category. |
|
200
|
This may then require that you generate a more complicated “chain” of |
|
201
|
certificates for Fossil to use here, without which the client may not be |
|
202
|
able to get back to a CA root it trusts. This is true regardless of |
|
203
|
whether that client is another copy of Fossil or a web browser |
|
204
|
traversing Fossil’s web UI, though that fact complicates matters by |
|
205
|
allowing for multiple classes of client, each of which may have their |
|
206
|
own rules for modifying the stock certificate scheme. |
|
207
|
|
|
208
|
This is distressingly common, in fact: Fossil links to OpenSSL to |
|
209
|
provide its TLS support, but there is a good chance that your browser |
|
210
|
uses another TLS implementation entirely. They may or may not agree on a |
|
211
|
single CA root store. |
|
212
|
|
|
213
|
How you accommodate all this complexity varies by the CA and other |
|
214
|
details. As but one example, Firefox’s “View Certificate” feature offers |
|
215
|
_two_ ways to download a given web site’s certificate: the cert alone or |
|
216
|
the “chain” leading back to the root. Depending on the use case, the |
|
217
|
standalone certificate might suffice, or you might need some type of |
|
218
|
cert chain. Complicating this is that the last link in the chain may be |
|
219
|
left off when it is for a mutually trusted CA root, implicitly |
|
220
|
completing the chain. |
|
221
|
|
|
222
|
[CAB]: https://en.wikipedia.org/wiki/CA/Browser_Forum |
|
223
|
|
|
224
|
## <a id="acme"></a>The ACME Protocol |
|
225
|
|
|
226
|
The [ACME Protocol][2] simplifies all this by automating the process of |
|
227
|
proving to a recognized public CA that you are in control of a given |
|
228
|
website. Without this proof, no valid CA will issue a cert for that |
|
229
|
domain, as that allows fraudulent impersonation. |
|
230
|
|
|
231
|
The primary implementation of ACME is [certbot], a product of the Let’s |
|
232
|
Encrypt organization. |
|
233
|
Here is, in a nutshell, what certbot will do to obtain your cert: |
|
234
|
|
|
235
|
1. It sends your "signing request" (the document that contains |
|
236
|
your public key and your domain name) to the CA. |
|
237
|
|
|
238
|
2. After receiving the signing request, the CA needs to verify that |
|
239
|
you control the domain of the cert. One of several methods certbot has |
|
240
|
for accomplishing this is to create a secret token and place it at |
|
241
|
a well-known location, then tell the CA about it over ACME. |
|
242
|
|
|
243
|
3. The CA then tries pulling that token, which if successful proves |
|
244
|
that the requester is able to create arbitrary data on the server, |
|
245
|
implicitly proving control over that server. This must be done |
|
246
|
over the unencrypted HTTP protocol since TLS isn’t working yet. |
|
247
|
|
|
248
|
4. If satisfied by this proof of control, the CA then creates the |
|
249
|
keypair described above and bakes the public half into the |
|
250
|
certificate it signs. It then sends this and the private half of |
|
251
|
the key back to certbot. |
|
252
|
|
|
253
|
5. Certbot stores these halves separately for the reasons sketched |
|
254
|
out above. |
|
255
|
|
|
256
|
6. It then deletes the secret one-time-use token it used to prove |
|
257
|
domain control. ACME’s design precludes replay attacks. |
|
258
|
|
|
259
|
In order for all of this to happen, certbot needs to be able to create |
|
260
|
a subdirectory named ".well-known", within a directory you specify, |
|
261
|
then populate that subdirectory with a token file of some kind. To support |
|
262
|
this, the "[fossil server](/help/server)" and |
|
263
|
"[fossil http](/help/http)" commands have the --acme option. |
|
264
|
|
|
265
|
When specified, Fossil sees a URL where the path |
|
266
|
begins with ".well-known", then instead of doing its normal processing, it |
|
267
|
looks for a file with that pathname and returns it to the client. If |
|
268
|
the "server" or "http" command is referencing a single Fossil repository, |
|
269
|
then the ".well-known" sub-directory should be in the same directory as |
|
270
|
the repository file. If the "server" or "http" command are run against |
|
271
|
a directory full of Fossil repositories, then the ".well-known" sub-directory |
|
272
|
should be in that top-level directory. |
|
273
|
|
|
274
|
Thus, to set up a project website, you should first run Fossil in ordinary |
|
275
|
unencrypted HTTP mode like this: |
|
276
|
|
|
277
|
fossil server --port 80 --acme /home/www/myproject.fossil |
|
278
|
|
|
279
|
Then you create your public/private key pair and run certbot, giving it |
|
280
|
a --webroot of /home/www. Certbot will create the sub-directory |
|
281
|
named "/home/www/.well-known" and put token files there, which the CA |
|
282
|
will verify. Then certbot will store your new cert in a particular file. |
|
283
|
|
|
284
|
Once certbot has obtained your cert, you may either pass the two halves |
|
285
|
to Fossil separately using the `--pkey` and `--cert` options described |
|
286
|
above, or you may concatenate them and pass that via `--cert` alone. |
|
287
|
|
|
288
|
[2]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment |
|
289
|
[certbot]: https://certbot.eff.org |
|
290
|
|