Fossil SCM

fossil-scm / src / http_ssl.c
Blame History Raw 1254 lines
1
/*
2
** Copyright (c) 2009 D. Richard Hipp
3
**
4
** This program is free software; you can redistribute it and/or
5
** modify it under the terms of the Simplified BSD License (also
6
** known as the "2-Clause License" or "FreeBSD License".)
7
**
8
** This program is distributed in the hope that it will be useful,
9
** but without any warranty; without even the implied warranty of
10
** merchantability or fitness for a particular purpose.
11
**
12
** Author contact information:
13
** [email protected]
14
** http://www.hwaci.com/drh/
15
**
16
*******************************************************************************
17
**
18
** This file manages low-level SSL communications.
19
**
20
** This file implements a singleton. A single SSL connection may be active
21
** at a time. State information is stored in static variables.
22
**
23
** The SSL connections can be either a client or a server. But all
24
** connections for a single process must be of the same type, either client
25
** or server.
26
**
27
** SSL support is abstracted out into this module because Fossil can
28
** be compiled without SSL support (which requires OpenSSL library)
29
*/
30
31
#include "config.h"
32
#include "http_ssl.h"
33
34
#ifdef FOSSIL_ENABLE_SSL
35
36
#include <openssl/bio.h>
37
#include <openssl/ssl.h>
38
#include <openssl/err.h>
39
#include <openssl/x509.h>
40
#include <openssl/x509v3.h>
41
42
#include <assert.h>
43
#include <sys/types.h>
44
45
/*
46
** There can only be a single OpenSSL IO connection open at a time.
47
** State information about that IO is stored in the following
48
** local variables:
49
*/
50
static int sslIsInit = 0; /* 0: uninit 1: init as client 2: init as server */
51
static BIO *iBio = 0; /* OpenSSL I/O abstraction */
52
static char *sslErrMsg = 0; /* Text of most recent OpenSSL error */
53
static SSL_CTX *sslCtx; /* SSL context */
54
static SSL *ssl;
55
static struct { /* Accept this SSL cert for this session only */
56
char *zHost; /* Subject or host name */
57
char *zHash; /* SHA2-256 hash of the cert */
58
} sException;
59
static int sslNoCertVerify = 0; /* Do not verify SSL certs */
60
61
62
/* This is a self-signed cert in the PEM format that can be used when
63
** no other certs are available.
64
*/
65
static const char sslSelfCert[] =
66
"-----BEGIN CERTIFICATE-----\n"
67
"MIIDMTCCAhkCFGrDmuJkkzWERP/ITBvzwwI2lv0TMA0GCSqGSIb3DQEBCwUAMFQx\n"
68
"CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOQzESMBAGA1UEBwwJQ2hhcmxvdHRlMRMw\n"
69
"EQYDVQQKDApGb3NzaWwtU0NNMQ8wDQYDVQQDDAZGb3NzaWwwIBcNMjExMjI3MTEz\n"
70
"MTU2WhgPMjEyMTEyMjcxMTMxNTZaMFQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJO\n"
71
"QzESMBAGA1UEBwwJQ2hhcmxvdHRlMRMwEQYDVQQKDApGb3NzaWwtU0NNMQ8wDQYD\n"
72
"VQQDDAZGb3NzaWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCCbTU2\n"
73
"6GRQHQqLq7vyZ0OxpAxmgfAKCxt6eIz+jBi2ZM/CB5vVXWVh2+SkSiWEA3UZiUqX\n"
74
"xZlzmS/CglZdiwLLDJML8B4OiV72oivFH/vJ7+cbvh1dTxnYiHuww7GfQngPrLfe\n"
75
"fiIYPDk1GTUJHBQ7Ue477F7F8vKuHdVgwktF/JDM6M60aSqlo2D/oysirrb+dlur\n"
76
"Tlv0rjsYOfq6bLAajoL3qi/vek6DNssoywbge4PfbTgS9g7Gcgncbcet5pvaS12J\n"
77
"avhFcd4JU4Ity49Hl9S/C2MfZ1tE53xVggRwKz4FPj65M5uymTdcxtjKXtCxIE1k\n"
78
"KxJxXQh7rIYjm+RTAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFkdtpqcybAzJN8G\n"
79
"+ONuUm5sXNbWta7JGvm8l0BTSBcCUtJA3hn16iJqXA9KmLnaF2denC4EYk+KlVU1\n"
80
"QXxskPJ4jB8A5B05jMijYv0nzCxKhviI8CR7GLEEGKzeg9pbW0+O3vaVehoZtdFX\n"
81
"z3SsCssr9QjCLiApQxMzW1Iv3od2JXeHBwfVMFrWA1VCEUCRs8OSW/VOqDPJLVEi\n"
82
"G6wxc4kN9dLK+5S29q3nzl24/qzXoF8P9Re5KBCbrwaHgy+OEEceq5jkmfGFxXjw\n"
83
"pvVCNry5uAhH5NqbXZampUWqiWtM4eTaIPo7Y2mDA1uWhuWtO6F9PsnFJlQHCnwy\n"
84
"s/TsrXk=\n"
85
"-----END CERTIFICATE-----\n";
86
87
/* This is the private-key corresponding to the cert above
88
*/
89
static const char sslSelfPKey[] =
90
"-----BEGIN PRIVATE KEY-----\n"
91
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCCbTU26GRQHQqL\n"
92
"q7vyZ0OxpAxmgfAKCxt6eIz+jBi2ZM/CB5vVXWVh2+SkSiWEA3UZiUqXxZlzmS/C\n"
93
"glZdiwLLDJML8B4OiV72oivFH/vJ7+cbvh1dTxnYiHuww7GfQngPrLfefiIYPDk1\n"
94
"GTUJHBQ7Ue477F7F8vKuHdVgwktF/JDM6M60aSqlo2D/oysirrb+dlurTlv0rjsY\n"
95
"Ofq6bLAajoL3qi/vek6DNssoywbge4PfbTgS9g7Gcgncbcet5pvaS12JavhFcd4J\n"
96
"U4Ity49Hl9S/C2MfZ1tE53xVggRwKz4FPj65M5uymTdcxtjKXtCxIE1kKxJxXQh7\n"
97
"rIYjm+RTAgMBAAECggEANfTH1vc8yIe7HRzmm9lsf8jF+II4s2705y2H5qY+cvYx\n"
98
"nKtZJGOG1X0KkYy7CGoFv5K0cSUl3lS5FVamM/yWIzoIex/Sz2C1EIL2aI5as6ez\n"
99
"jB6SN0/J+XI8+Vt7186/rHxfdIPpxuzjHbxX3HTpScETNWcLrghbrPxakbTPPxwt\n"
100
"+x7QlPmmkFNuMfvkzToFf9NdwL++44TeBPOpvD/Lrw+eyqdth9RJPq9cM96plh9V\n"
101
"HuRqeD8+QNafaXBdSQs3FJK/cDK/vWGKZWIfFVSDbDhwYljkXGijreFjtXQfkkpF\n"
102
"rl1J87/H9Ee7z8fTD2YXQHl+0/rghAVtac3u54dpQQKBgQC2XG3OEeMrOp9dNkUd\n"
103
"F8VffUg0ecwG+9L3LCe7U71K0kPmXjV6xNnuYcNQu84kptc5vI8wD23p29LaxdNc\n"
104
"9m0lcw06/YYBOPkNphcHkINYZTvVJF10mL3isymzMaTtwDkZUkOjL1B+MTiFT/qp\n"
105
"ARKrTYGJ4HxY7+tUkI5pUmg4PQKBgQC3GA4d1Rz3Pb/RRpcsZgWknKsKhoN36mSn\n"
106
"xFJ3wPBvVv2B1ltTMzh/+the0ty6clzMrvoLERzRcheDsNrc/j/TUVG8sVdBYJwX\n"
107
"tMZyFW4NVMOErT/1ukh6jBqIMBo6NJL3EV/AKj0yniksgKOr0/AAduAccnGST8Jd\n"
108
"SHOdjwvHzwKBgGZBq/zqgNTDuYseHGE07CMgcDWkumiMGv8ozlq3mSR0hUiPOTPP\n"
109
"YFjQjyIdPXnF6FfiyPPtIvgIoNK2LVAqiod+XUPf152l4dnqcW13dn9BvOxGyPTR\n"
110
"lWCikFaAFviOWjY9r9m4dU1dslDmySqthFd0TZgPvgps9ivkJ0cdw30NAoGAMC/E\n"
111
"h1VvKiK2OP27C5ROJ+STn1GHiCfIFd81VQ8SODtMvL8NifgRBp2eFFaqgOdYRQZI\n"
112
"CGGYlAbS6XXCJCdF5Peh62dA75PdgN+y2pOJQzjrvB9cle9Q4++7i9wdCvSLOTr5\n"
113
"WDnFoWy+qVexu6crovOmR9ZWzYrwPFy1EOJ010ECgYBl7Q+jmjOSqsVwhFZ0U7LG\n"
114
"diN+vXhWfn1wfOWd8u79oaqU/Oy7xyKW2p3H5z2KFrBM/vib53Lh4EwFZjcX+jVG\n"
115
"krAmbL+M/hP7z3TD2UbESAzR/c6l7FU45xN84Lsz5npkR8H/uAHuqLgb9e430Mjx\n"
116
"YNMwdb8rChHHChNZu6zuxw==\n"
117
"-----END PRIVATE KEY-----\n";
118
119
/*
120
** Read a PEM certificate from memory and push it into an SSL_CTX.
121
** Return the number of errors.
122
*/
123
static int sslctx_use_cert_from_mem(
124
SSL_CTX *ctx,
125
const char *pData,
126
int nData
127
){
128
BIO *in;
129
int rc = 1;
130
X509 *x = 0;
131
X509 *cert = 0;
132
133
in = BIO_new_mem_buf(pData, nData);
134
if( in==0 ) goto end_of_ucfm;
135
/* x = X509_new_ex(ctx->libctx, ctx->propq); */
136
x = X509_new();
137
if( x==0 ) goto end_of_ucfm;
138
cert = PEM_read_bio_X509(in, &x, 0, 0);
139
if( cert==0 ) goto end_of_ucfm;
140
rc = SSL_CTX_use_certificate(ctx, x)<=0;
141
end_of_ucfm:
142
X509_free(x);
143
BIO_free(in);
144
return rc;
145
}
146
147
/*
148
** Read a PEM private key from memory and add it to an SSL_CTX.
149
** Return the number of errors.
150
*/
151
static int sslctx_use_pkey_from_mem(
152
SSL_CTX *ctx,
153
const char *pData,
154
int nData
155
){
156
int rc = 1;
157
BIO *in;
158
EVP_PKEY *pkey = 0;
159
160
in = BIO_new_mem_buf(pData, nData);
161
if( in==0 ) goto end_of_upkfm;
162
pkey = PEM_read_bio_PrivateKey(in, 0, 0, 0);
163
if( pkey==0 ) goto end_of_upkfm;
164
rc = SSL_CTX_use_PrivateKey(ctx, pkey)<=0;
165
EVP_PKEY_free(pkey);
166
end_of_upkfm:
167
BIO_free(in);
168
return rc;
169
}
170
171
/*
172
** Clear the SSL error message
173
*/
174
static void ssl_clear_errmsg(void){
175
free(sslErrMsg);
176
sslErrMsg = 0;
177
}
178
179
/*
180
** Set the SSL error message.
181
*/
182
void ssl_set_errmsg(const char *zFormat, ...){
183
va_list ap;
184
ssl_clear_errmsg();
185
va_start(ap, zFormat);
186
sslErrMsg = vmprintf(zFormat, ap);
187
va_end(ap);
188
}
189
190
/*
191
** Return the current SSL error message
192
*/
193
const char *ssl_errmsg(void){
194
return sslErrMsg;
195
}
196
197
/*
198
** When a server requests a client certificate that hasn't been provided,
199
** display a warning message explaining what to do next.
200
*/
201
static int ssl_client_cert_callback(SSL *ssl, X509 **x509, EVP_PKEY **pkey){
202
fossil_warning("The remote server requested a client certificate for "
203
"authentication. Specify the pathname to a file containing the PEM "
204
"encoded certificate and private key with the --ssl-identity option "
205
"or the ssl-identity setting.");
206
return 0; /* no cert available */
207
}
208
209
/*
210
** Convert an OpenSSL ASN1_TIME to an ISO8601 timestamp.
211
**
212
** Per RFC 5280, ASN1 timestamps in X.509 certificates must
213
** be in UTC (Zulu timezone) with no fractional seconds.
214
**
215
** If showUtc==1, add " UTC" at the end of the returned string. This is
216
** not ISO8601-compliant, but makes the displayed value more user-friendly.
217
*/
218
static const char *ssl_asn1time_to_iso8601(ASN1_TIME *asn1_time,
219
int showUtc){
220
assert( showUtc==0 || showUtc==1 );
221
if( !ASN1_TIME_check(asn1_time) ){
222
return mprintf("Bad time value");
223
}else{
224
char res[20];
225
char *pr = res;
226
#if OPENSSL_VERSION_NUMBER < 0x10100000L
227
#define ASN1_STRING_get0_data ASN1_STRING_data
228
#endif
229
const char *pt = (const char *)ASN1_STRING_get0_data(asn1_time);
230
/* 0123456789 1234
231
** UTCTime: YYMMDDHHMMSSZ (YY >= 50 ? 19YY : 20YY)
232
** GeneralizedTime: YYYYMMDDHHMMSSZ */
233
if( ASN1_STRING_length(asn1_time) < 15 ){
234
/* UTCTime, fill out century digits */
235
*pr++ = pt[0]>='5' ? '1' : '2';
236
*pr++ = pt[0]>='5' ? '9' : '0';
237
}else{
238
/* GeneralizedTime, copy century digits and advance source */
239
*pr++ = pt[0]; *pr++ = pt[1];
240
pt += 2;
241
}
242
*pr++ = pt[0]; *pr++ = pt[1]; *pr++ = '-';
243
*pr++ = pt[2]; *pr++ = pt[3]; *pr++ = '-';
244
*pr++ = pt[4]; *pr++ = pt[5]; *pr++ = ' ';
245
*pr++ = pt[6]; *pr++ = pt[7]; *pr++ = ':';
246
*pr++ = pt[8]; *pr++ = pt[9]; *pr++ = ':';
247
*pr++ = pt[10]; *pr++ = pt[11]; *pr = '\0';
248
return mprintf("%s%s", res, (showUtc ? " UTC" : ""));
249
}
250
}
251
252
/*
253
** Call this routine once before any other use of the SSL interface.
254
** This routine does initial configuration of the SSL module.
255
*/
256
static void ssl_global_init_client(void){
257
const char *identityFile;
258
259
if( sslIsInit==0 ){
260
const char *zFile;
261
const char *zCaFile = 0;
262
const char *zCaDirectory = 0;
263
int i;
264
265
SSL_library_init();
266
SSL_load_error_strings();
267
OpenSSL_add_all_algorithms();
268
sslCtx = SSL_CTX_new(SSLv23_client_method());
269
/* Disable SSLv2 and SSLv3 */
270
SSL_CTX_set_options(sslCtx, SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3);
271
272
/* Find the trust store */
273
zFile = 0;
274
for(i=0; zFile==0 && i<5; i++){
275
switch( i ){
276
case 0: /* First priority is environment variables */
277
zFile = fossil_getenv(X509_get_default_cert_file_env());
278
break;
279
case 1:
280
zFile = fossil_getenv(X509_get_default_cert_dir_env());
281
break;
282
case 2:
283
if( !g.repositoryOpen ) db_open_config(0,0);
284
zFile = db_get("ssl-ca-location",0);
285
break;
286
case 3:
287
zFile = X509_get_default_cert_file();
288
break;
289
case 4:
290
zFile = X509_get_default_cert_dir();
291
break;
292
}
293
if( zFile==0 ) continue;
294
switch( file_isdir(zFile, ExtFILE) ){
295
case 0: { /* doesn't exist */
296
zFile = 0;
297
break;
298
}
299
case 1: { /* directory */
300
zCaFile = 0;
301
zCaDirectory = zFile;
302
break;
303
}
304
case 2: { /* file */
305
zCaFile = zFile;
306
zCaDirectory = 0;
307
break;
308
}
309
}
310
}
311
if( zFile==0 ){
312
/* fossil_fatal("Cannot find a trust store"); */
313
}else if( SSL_CTX_load_verify_locations(sslCtx, zCaFile, zCaDirectory)==0 ){
314
fossil_fatal("Cannot load CA root certificates from %s", zFile);
315
}
316
317
/* Enable OpenSSL to use the Windows system ROOT certificate store to search for
318
** certificates missing in the file and directory trust stores already loaded by
319
** `SSL_CTX_load_verify_locations()'.
320
** This feature was introduced with OpenSSL 3.2.0, and may be enabled by default
321
** for future versions of OpenSSL, and explicit initialization may be redundant.
322
** NOTE TO HACKERS TWEAKING THEIR OPENSSL CONFIGURATION:
323
** The following OpenSSL configuration options must not be used for this feature
324
** to be available: `no-autoalginit', `no-winstore'. The Fossil makefiles do not
325
** currently set these options when building OpenSSL for Windows. */
326
#if defined(_WIN32)
327
#if OPENSSL_VERSION_NUMBER >= 0x030200000
328
if( SSLeay()!=0x30500000 /* Don't use for 3.5.0 due to a bug */
329
&& SSL_CTX_load_verify_store(sslCtx, "org.openssl.winstore:")==0
330
){
331
fossil_print("NOTICE: Failed to load the Windows root certificates.\n");
332
}
333
#endif /* OPENSSL_VERSION_NUMBER >= 0x030200000 */
334
#endif /* _WIN32 */
335
336
/* Load client SSL identity, preferring the filename specified on the
337
** command line */
338
if( g.zSSLIdentity!=0 ){
339
identityFile = g.zSSLIdentity;
340
}else{
341
identityFile = db_get("ssl-identity", 0);
342
}
343
if( identityFile!=0 && identityFile[0]!='\0' ){
344
if( SSL_CTX_use_certificate_chain_file(sslCtx,identityFile)!=1
345
|| SSL_CTX_use_PrivateKey_file(sslCtx,identityFile,SSL_FILETYPE_PEM)!=1
346
){
347
fossil_fatal("Could not load SSL identity from %s", identityFile);
348
}
349
}
350
/* Register a callback to tell the user what to do when the server asks
351
** for a cert */
352
SSL_CTX_set_client_cert_cb(sslCtx, ssl_client_cert_callback);
353
354
sslIsInit = 1;
355
}else{
356
assert( sslIsInit==1 );
357
}
358
}
359
360
/*
361
** Call this routine to shutdown the SSL module prior to program exit.
362
*/
363
void ssl_global_shutdown(void){
364
if( sslIsInit ){
365
SSL_CTX_free(sslCtx);
366
ssl_clear_errmsg();
367
sslIsInit = 0;
368
}
369
socket_global_shutdown();
370
}
371
372
/*
373
** Close the currently open client SSL connection. If no connection is open,
374
** this routine is a no-op.
375
*/
376
void ssl_close_client(void){
377
if( iBio!=NULL ){
378
(void)BIO_reset(iBio);
379
BIO_free_all(iBio);
380
iBio = NULL;
381
}
382
socket_close();
383
}
384
385
/*
386
** Return the host name of the server that pUrlData connects to, without
387
** a port number. When the connection goes through a proxy,
388
** pUrlData->name holds the proxy hostname, and the server hostname is in
389
** pUrlData->proxyOrigName.
390
*/
391
static const char *ssl_server_name(const UrlData *pUrlData){
392
return pUrlData->useProxy ? pUrlData->proxyOrigName : pUrlData->name;
393
}
394
395
/* See RFC2817 for details */
396
static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
397
int rc, httpVerMin;
398
char *bbuf;
399
Blob snd, reply;
400
int done=0,end=0;
401
const char *zHost = ssl_server_name(pUrlData);
402
const char *zLb = strchr(zHost, ':') ? "[" : ""; /* IPv6 brackets */
403
const char *zRb = zLb[0] ? "]" : "";
404
blob_zero(&snd);
405
blob_appendf(&snd, "CONNECT %s%s%s:%d HTTP/1.1\r\n",
406
zLb, zHost, zRb, pUrlData->proxyOrigPort);
407
blob_appendf(&snd, "Host: %s%s%s:%d\r\n",
408
zLb, zHost, zRb, pUrlData->proxyOrigPort);
409
if( pUrlData->proxyAuth ){
410
blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
411
}
412
blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
413
blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
414
blob_append(&snd, "\r\n", 2);
415
BIO_write(bio, blob_buffer(&snd), blob_size(&snd));
416
blob_reset(&snd);
417
418
/* Wait for end of reply */
419
blob_zero(&reply);
420
do{
421
int len;
422
char buf[256];
423
len = BIO_read(bio, buf, sizeof(buf));
424
blob_append(&reply, buf, len);
425
426
bbuf = blob_buffer(&reply);
427
len = blob_size(&reply);
428
while(end < len) {
429
if( bbuf[end]=='\n' ) {
430
if( (end+1<len && bbuf[end+1]=='\n')
431
|| (end+2<len && bbuf[end+1]=='\r' && bbuf[end+2]=='\n')
432
){
433
done = 1;
434
break;
435
}
436
}
437
end++;
438
}
439
}while(!done);
440
sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
441
blob_reset(&reply);
442
return rc;
443
}
444
445
/*
446
** Invoke this routine to disable SSL cert verification. After
447
** this call is made, any SSL cert that the server provides will
448
** be accepted. Communication will still be encrypted, but the
449
** client has no way of knowing whether it is talking to the
450
** real server or a man-in-the-middle imposter.
451
*/
452
void ssl_disable_cert_verification(void){
453
sslNoCertVerify = 1;
454
}
455
456
/*
457
** Return true if zHost is an IPv4 or IPv6 address. A certificate
458
** lists an IP address separately from its DNS names, and RFC 6066 does not
459
** permit an IP address as the TLS server name.
460
*/
461
static int ssl_host_is_ip_address(const char *zHost){
462
ASN1_OCTET_STRING *pIp = a2i_IPADDRESS(zHost);
463
if( pIp==0 ){
464
ERR_clear_error();
465
return 0;
466
}
467
ASN1_OCTET_STRING_free(pIp);
468
return 1;
469
}
470
471
/*
472
** Return true if zHost contains a byte outside ASCII. RFC 6066 permits
473
** only an ASCII DNS name as the TLS server name, so an internationalized
474
** domain name would have to be sent in its "xn--" form, but Fossil does not
475
** use that form.
476
*/
477
static int ssl_host_is_non_ascii(const char *zHost){
478
while( *zHost ){
479
if( (unsigned char)*zHost >= 0x80 ) return 1;
480
zHost++;
481
}
482
return 0;
483
}
484
485
/*
486
** Open an SSL connection as a client that is to connect to the server
487
** identified by pUrlData.
488
**
489
* The identify of the server is determined as follows:
490
**
491
** pUrlData->name Name of the server. Ex: fossil-scm.org
492
** g.url.name Name of the proxy server, if proxying.
493
** pUrlData->port TCP/IP port to use. Ex: 80
494
**
495
** Return the number of errors.
496
*/
497
int ssl_open_client(UrlData *pUrlData){
498
X509 *cert;
499
const char *zRemoteHost;
500
const char *zTlsName; /* zRemoteHost needed by the TLS layer */
501
char zDotless[256]; /* zRemoteHost without a trailing dot */
502
int isIpAddr; /* True if zRemoteHost is an IP address */
503
BIO *sBio;
504
505
ssl_global_init_client();
506
if( socket_open(pUrlData) ){
507
ssl_set_errmsg("SSL: cannot open socket (%s)", socket_errmsg());
508
return 1;
509
}
510
sBio = BIO_new_socket(socket_get_fd(), 0);
511
if( pUrlData->useProxy ){
512
int rc = establish_proxy_tunnel(pUrlData, sBio);
513
if( rc<200||rc>299 ){
514
ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
515
ssl_close_client();
516
return 1;
517
}
518
519
pUrlData->path = pUrlData->proxyUrlPath;
520
}
521
iBio = BIO_new_ssl(sslCtx, 1);
522
BIO_push(iBio, sBio);
523
BIO_set_ssl(sBio, ssl, BIO_NOCLOSE);
524
BIO_set_ssl_mode(iBio, 1);
525
BIO_get_ssl(iBio, &ssl);
526
527
zRemoteHost = ssl_server_name(pUrlData);
528
/* A fully qualified name may end with a dot, as in "example.com.".
529
** The RFC 6066 TLS server name and all certificate names are
530
** dotless */
531
zTlsName = zRemoteHost;
532
{
533
size_t n = strlen(zRemoteHost);
534
if( n>1 && zRemoteHost[n-1]=='.' && n<sizeof(zDotless) ){
535
memcpy(zDotless, zRemoteHost, n-1);
536
zDotless[n-1] = 0;
537
zTlsName = zDotless;
538
}
539
}
540
isIpAddr = ssl_host_is_ip_address(zTlsName);
541
542
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
543
if( !isIpAddr && !ssl_host_is_non_ascii(zTlsName)
544
&& !SSL_set_tlsext_host_name(ssl, zTlsName)
545
){
546
fossil_warning("WARNING: failed to set server name indication (SNI), "
547
"continuing without it.\n");
548
}
549
#endif
550
551
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
552
#if OPENSSL_VERSION_NUMBER >= 0x010002000
553
if( !sslNoCertVerify ){
554
X509_VERIFY_PARAM *param = 0;
555
param = SSL_get0_param(ssl);
556
if( isIpAddr ){
557
if( !X509_VERIFY_PARAM_set1_ip_asc(param, zTlsName) ){
558
fossil_fatal("failed to set IP address.");
559
}
560
}else if( !X509_VERIFY_PARAM_set1_host(param, zTlsName,
561
strlen(zTlsName)) ){
562
fossil_fatal("failed to set hostname.");
563
}
564
/* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
565
}
566
#endif
567
568
if( BIO_do_handshake(iBio)<=0 ){
569
ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
570
zRemoteHost,
571
pUrlData->useProxy ? pUrlData->proxyOrigPort : pUrlData->port,
572
ERR_reason_error_string(ERR_get_error()));
573
ssl_close_client();
574
return 1;
575
}
576
/* Check if certificate is valid */
577
cert = SSL_get_peer_certificate(ssl);
578
579
if ( cert==NULL ){
580
ssl_set_errmsg("No SSL certificate was presented by the peer");
581
ssl_close_client();
582
return 1;
583
}
584
585
/* Debugging hint: On unix-like system, run something like:
586
**
587
** SSL_CERT_DIR=/tmp ./fossil sync
588
**
589
** to cause certificate validation to fail, and thus test the fallback
590
** logic.
591
*/
592
if( !sslNoCertVerify && SSL_get_verify_result(ssl)!=X509_V_OK ){
593
int x, desclen;
594
char *desc, *prompt;
595
Blob ans;
596
char cReply;
597
BIO *mem;
598
unsigned char md[EVP_MAX_MD_SIZE];
599
char zHash[EVP_MAX_MD_SIZE*2+1];
600
unsigned int mdLength = (int)sizeof(md);
601
602
memset(md, 0, sizeof(md));
603
zHash[0] = 0;
604
/* MMNNFFPPS */
605
#if OPENSSL_VERSION_NUMBER >= 0x010000000
606
x = X509_digest(cert, EVP_sha256(), md, &mdLength);
607
#else
608
x = X509_digest(cert, EVP_sha1(), md, &mdLength);
609
#endif
610
if( x ){
611
unsigned j;
612
for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
613
zHash[j*2] = "0123456789abcdef"[md[j]>>4];
614
zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
615
}
616
zHash[j*2] = 0;
617
}
618
619
if( ssl_certificate_exception_exists(pUrlData, zHash) ){
620
/* Ignore the failure because an exception exists */
621
ssl_one_time_exception(pUrlData, zHash);
622
}else{
623
/* Tell the user about the failure and ask what to do */
624
mem = BIO_new(BIO_s_mem());
625
BIO_puts(mem, " subject: ");
626
X509_NAME_print_ex(mem, X509_get_subject_name(cert), 0, XN_FLAG_ONELINE);
627
BIO_puts(mem, "\n issuer: ");
628
X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 0, XN_FLAG_ONELINE);
629
BIO_printf(mem, "\n notBefore: %s",
630
ssl_asn1time_to_iso8601(X509_get_notBefore(cert), 1));
631
BIO_printf(mem, "\n notAfter: %s",
632
ssl_asn1time_to_iso8601(X509_get_notAfter(cert), 1));
633
BIO_printf(mem, "\n sha256: %s", zHash);
634
desclen = BIO_get_mem_data(mem, &desc);
635
636
prompt = mprintf("Unable to verify SSL cert from %s\n%.*s\n"
637
"accept this cert and continue (y/N/fingerprint)? ",
638
zRemoteHost, desclen, desc);
639
BIO_free(mem);
640
641
prompt_user(prompt, &ans);
642
free(prompt);
643
cReply = blob_str(&ans)[0];
644
if( cReply!='y' && cReply!='Y'
645
&& fossil_stricmp(blob_str(&ans),zHash)!=0
646
){
647
X509_free(cert);
648
ssl_set_errmsg("SSL cert declined");
649
ssl_close_client();
650
blob_reset(&ans);
651
return 1;
652
}
653
blob_reset(&ans);
654
ssl_one_time_exception(pUrlData, zHash);
655
prompt_user("remember this exception (y/N)? ", &ans);
656
cReply = blob_str(&ans)[0];
657
if( cReply=='y' || cReply=='Y') {
658
db_open_config(0,0);
659
ssl_remember_certificate_exception(pUrlData, zHash);
660
}
661
blob_reset(&ans);
662
}
663
}
664
665
X509_free(cert);
666
return 0;
667
}
668
669
/*
670
** Remember that the cert with the given hash is acceptable for
671
** use with the server that pUrlData connects to.
672
*/
673
LOCAL void ssl_remember_certificate_exception(
674
UrlData *pUrlData,
675
const char *zHash
676
){
677
db_set_mprintf(zHash, 1, "cert:%s", ssl_server_name(pUrlData));
678
}
679
680
/*
681
** Return true if the there exists a certificate exception for
682
** the server that pUrlData connects to that matches the hash.
683
*/
684
LOCAL int ssl_certificate_exception_exists(
685
UrlData *pUrlData,
686
const char *zHash
687
){
688
char *zName, *zValue;
689
if( fossil_strcmp(sException.zHost,ssl_server_name(pUrlData))==0
690
&& fossil_strcmp(sException.zHash,zHash)==0
691
){
692
return 1;
693
}
694
zName = mprintf("cert:%s", ssl_server_name(pUrlData));
695
zValue = db_get(zName,0);
696
fossil_free(zName);
697
return zValue!=0 && strcmp(zHash,zValue)==0;
698
}
699
700
/*
701
** Remember zHash as an acceptable certificate for this session only.
702
*/
703
LOCAL void ssl_one_time_exception(
704
UrlData *pUrlData,
705
const char *zHash
706
){
707
fossil_free(sException.zHost);
708
sException.zHost = fossil_strdup(ssl_server_name(pUrlData));
709
fossil_free(sException.zHash);
710
sException.zHash = fossil_strdup(zHash);
711
}
712
713
/*
714
** Send content out over the SSL connection from the client to
715
** the server.
716
*/
717
size_t ssl_send(void *NotUsed, void *pContent, size_t N){
718
size_t total = 0;
719
while( N>0 ){
720
int sent = BIO_write(iBio, pContent, N);
721
if( sent<=0 ){
722
if( BIO_should_retry(iBio) ){
723
continue;
724
}
725
break;
726
}
727
total += sent;
728
N -= sent;
729
pContent = (void*)&((char*)pContent)[sent];
730
}
731
return total;
732
}
733
734
/*
735
** Receive content back from the client SSL connection. In other
736
** words read the reply back from the server.
737
*/
738
size_t ssl_receive(void *NotUsed, void *pContent, size_t N){
739
size_t total = 0;
740
while( N>0 ){
741
int got = BIO_read(iBio, pContent, N);
742
if( got<=0 ){
743
if( BIO_should_retry(iBio) ){
744
continue;
745
}
746
break;
747
}
748
total += got;
749
N -= got;
750
pContent = (void*)&((char*)pContent)[got];
751
}
752
return total;
753
}
754
755
/*
756
** Initialize the SSL library so that it is able to handle
757
** server-side connections. Invoke fossil_fatal() if there are
758
** any problems.
759
**
760
** If zKeyFile and zCertFile are not NULL, then they are the names
761
** of disk files that hold the certificate and private-key for the
762
** server. If zCertFile is not NULL but zKeyFile is NULL, then
763
** zCertFile is assumed to be a concatenation of the certificate and
764
** the private-key in the PEM format.
765
**
766
** If zCertFile is "unsafe-builtin", then a built-in self-signed cert
767
** is used. This built-in cert is insecure and should only be used for
768
** testing and debugging.
769
*/
770
void ssl_init_server(const char *zCertFile, const char *zKeyFile){
771
if( sslIsInit==0 && zCertFile ){
772
SSL_library_init();
773
SSL_load_error_strings();
774
OpenSSL_add_all_algorithms();
775
sslCtx = SSL_CTX_new(SSLv23_server_method());
776
if( sslCtx==0 ){
777
ERR_print_errors_fp(stderr);
778
fossil_fatal("Error initializing the SSL server");
779
}
780
if( fossil_strcmp(zCertFile,"unsafe-builtin")==0 ){
781
if( sslctx_use_cert_from_mem(sslCtx, sslSelfCert, -1)
782
|| sslctx_use_pkey_from_mem(sslCtx, sslSelfPKey, -1)
783
){
784
fossil_fatal("Error loading self-signed CERT and KEY");
785
}
786
}else{
787
if( SSL_CTX_use_certificate_chain_file(sslCtx,zCertFile)!=1 ){
788
ERR_print_errors_fp(stderr);
789
fossil_fatal("Error loading CERT file \"%s\"", zCertFile);
790
}
791
if( zKeyFile==0 ) zKeyFile = zCertFile;
792
if( SSL_CTX_use_PrivateKey_file(sslCtx, zKeyFile, SSL_FILETYPE_PEM)<=0 ){
793
ERR_print_errors_fp(stderr);
794
if( strcmp(zKeyFile,zCertFile)==0 ){
795
fossil_fatal("The private key is not found in \"%s\". "
796
"Either append the private key to the certification in that "
797
"file or use a separate --pkey option to specify the private key.",
798
zKeyFile);
799
}else{
800
fossil_fatal("Error loading the private key from file \"%s\"",
801
zKeyFile);
802
}
803
}
804
}
805
if( !SSL_CTX_check_private_key(sslCtx) ){
806
fossil_fatal("PRIVATE KEY \"%s\" does not match CERT \"%s\"",
807
zKeyFile, zCertFile);
808
}
809
SSL_CTX_set_mode(sslCtx, SSL_MODE_AUTO_RETRY);
810
sslIsInit = 2;
811
}else{
812
assert( sslIsInit==2 );
813
}
814
}
815
816
typedef struct SslServerConn {
817
SSL *ssl; /* The SSL codec */
818
int iSocket; /* The socket */
819
BIO *bio; /* BIO object. Needed for EOF detection. */
820
} SslServerConn;
821
822
/*
823
** Create a new server-side codec. The argument is the socket's file
824
** descriptor from which the codec reads and writes. The returned
825
** memory must eventually be passed to ssl_close_server().
826
*/
827
void *ssl_new_server(int iSocket){
828
SslServerConn *pServer = fossil_malloc_zero(sizeof(*pServer));
829
BIO *b = BIO_new_socket(iSocket, 0);
830
pServer->ssl = SSL_new(sslCtx);
831
pServer->iSocket = iSocket;
832
pServer->bio = b;
833
SSL_set_bio(pServer->ssl, b, b);
834
SSL_accept(pServer->ssl);
835
return (void*)pServer;
836
}
837
838
/*
839
** Close a server-side code previously returned from ssl_new_server().
840
*/
841
void ssl_close_server(void *pServerArg){
842
SslServerConn *pServer = (SslServerConn*)pServerArg;
843
SSL_free(pServer->ssl);
844
fossil_free(pServer);
845
}
846
847
/*
848
** Return TRUE if there are no more bytes available to be read from
849
** the client.
850
*/
851
int ssl_eof(void *pServerArg){
852
SslServerConn *pServer = (SslServerConn*)pServerArg;
853
return BIO_eof(pServer->bio);
854
}
855
856
/*
857
** Read cleartext bytes that have been received from the client and
858
** decrypted by the SSL server codec.
859
**
860
** If the expected payload size unknown, i.e. if the HTTP
861
** Content-Length: header field has not been parsed, the doLoop
862
** argument should be 0, or SSL_read() may block and wait for more
863
** data than is eventually going to arrive (on Windows). On
864
** non-Windows builds, it has been our experience that the final
865
** argument must always be true, as discussed at length at:
866
**
867
** https://fossil-scm.org/forum/forumpost/2f818850abb72719
868
*/
869
size_t ssl_read_server(void *pServerArg, char *zBuf, size_t nBuf, int doLoop){
870
int n;
871
size_t rc = 0;
872
SslServerConn *pServer = (SslServerConn*)pServerArg;
873
if( nBuf>0x7fffffff ){ fossil_fatal("SSL read too big"); }
874
while( nBuf!=rc && BIO_eof(pServer->bio)==0 ){
875
n = SSL_read(pServer->ssl, zBuf + rc, (int)(nBuf - rc));
876
if( n>0 ){
877
rc += n;
878
}
879
if( doLoop==0 || n<=0 ){
880
break;
881
}
882
}
883
return rc;
884
}
885
886
/*
887
** Read a single line of text from the client, up to nBuf-1 bytes. On
888
** success, writes nBuf-1 bytes to zBuf and NUL-terminates zBuf.
889
** Returns NULL on an I/O error or at EOF.
890
*/
891
char *ssl_gets(void *pServerArg, char *zBuf, int nBuf){
892
int n = 0;
893
int i;
894
SslServerConn *pServer = (SslServerConn*)pServerArg;
895
896
if( BIO_eof(pServer->bio) ) return 0;
897
for(i=0; i<nBuf-1; i++){
898
n = SSL_read(pServer->ssl, &zBuf[i], 1);
899
if( n<=0 ){
900
return 0;
901
}
902
if( zBuf[i]=='\n' ) break;
903
}
904
zBuf[i+1] = 0;
905
return zBuf;
906
}
907
908
909
/*
910
** Write cleartext bytes into the SSL server codec so that they can
911
** be encrypted and sent back to the client.
912
*/
913
size_t ssl_write_server(void *pServerArg, char *zBuf, size_t nBuf){
914
int n;
915
SslServerConn *pServer = (SslServerConn*)pServerArg;
916
if( nBuf<=0 ) return 0;
917
if( nBuf>0x7fffffff ){ fossil_fatal("SSL write too big"); }
918
n = SSL_write(pServer->ssl, zBuf, (int)nBuf);
919
if( n<=0 ){
920
return -SSL_get_error(pServer->ssl, n);
921
}else{
922
return n;
923
}
924
}
925
926
#endif /* FOSSIL_ENABLE_SSL */
927
928
#ifdef FOSSIL_ENABLE_SSL
929
/*
930
** zPath is a name that might be a file or directory containing a trust
931
** store. *pzStore is the name of the trust store to actually use.
932
**
933
** If *pzStore is not NULL (meaning no trust store has been found yet)
934
** and if zPath exists, then set *pzStore to point to zPath.
935
*/
936
static void trust_location_usable(const char *zPath, const char **pzStore){
937
if( *pzStore!=0 ) return;
938
if( file_isdir(zPath, ExtFILE)>0 ) *pzStore = zPath;
939
}
940
#endif /* FOSSIL_ENABLE_SSL */
941
942
/*
943
** COMMAND: tls-config* abbrv-subcom
944
** COMMAND: ssl-config abbrv-subcom
945
**
946
** Usage: %fossil ssl-config [SUBCOMMAND] [OPTIONS...] [ARGS...]
947
**
948
** This command is used to view or modify the TLS (Transport Layer
949
** Security) configuration for Fossil. TLS (formerly SSL) is the
950
** encryption technology used for secure HTTPS transport.
951
**
952
** Sub-commands:
953
**
954
** remove-exception DOMAINS Remove TLS cert exceptions for the domains
955
** listed. Or remove them all if the --all
956
** option is specified.
957
**
958
** scrub ?--force? Remove all SSL configuration data from the
959
** repository. Use --force to omit the
960
** confirmation.
961
**
962
** show ?-v? Show the TLS configuration. Add -v to see
963
** additional explanation
964
*/
965
void test_tlsconfig_info(void){
966
const char *zCmd;
967
size_t nCmd;
968
int nHit = 0;
969
970
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
971
db_open_config(1,0);
972
if( g.argc==2 || (g.argc>=3 && g.argv[2][0]=='-') ){
973
zCmd = "show";
974
nCmd = 4;
975
}else{
976
zCmd = g.argv[2];
977
nCmd = strlen(zCmd);
978
}
979
if( strncmp("scrub",zCmd,nCmd)==0 && nCmd>4 ){
980
int bForce = find_option("force","f",0)!=0;
981
verify_all_options();
982
if( !bForce ){
983
Blob ans;
984
char cReply;
985
prompt_user(
986
"Scrubbing the SSL configuration will permanently delete information.\n"
987
"Changes cannot be undone. Continue (y/N)? ", &ans);
988
cReply = blob_str(&ans)[0];
989
if( cReply!='y' && cReply!='Y' ){
990
fossil_exit(1);
991
}
992
}
993
db_unprotect(PROTECT_ALL);
994
db_multi_exec(
995
"PRAGMA secure_delete=ON;"
996
"DELETE FROM config WHERE name GLOB 'ssl-*';"
997
);
998
db_protect_pop();
999
}else
1000
if( strncmp("show",zCmd,nCmd)==0 ){
1001
#if defined(FOSSIL_ENABLE_SSL)
1002
const char *zName, *zValue;
1003
const char *zUsed = 0; /* Trust store location actually used */
1004
size_t nName;
1005
#endif
1006
Stmt q;
1007
int verbose = find_option("verbose","v",0)!=0;
1008
verify_all_options();
1009
1010
#if !defined(FOSSIL_ENABLE_SSL)
1011
fossil_print("OpenSSL-version: (none)\n");
1012
if( verbose ){
1013
fossil_print("\n"
1014
" The OpenSSL library is not used by this build of Fossil\n\n"
1015
);
1016
}
1017
#else
1018
fossil_print("OpenSSL-version: %s (0x%09llx)\n",
1019
SSLeay_version(SSLEAY_VERSION), (unsigned long long)SSLeay());
1020
if( verbose ){
1021
fossil_print("\n"
1022
" The version of the OpenSSL library being used\n"
1023
" by this instance of Fossil. Version 3.0.0 or\n"
1024
" later is recommended.\n\n"
1025
);
1026
}
1027
1028
fossil_print("Trust store location\n");
1029
zName = X509_get_default_cert_file_env();
1030
zValue = fossil_getenv(zName);
1031
if( zValue==0 ) zValue = "";
1032
trust_location_usable(zValue, &zUsed);
1033
nName = strlen(zName);
1034
fossil_print(" %s:%*s%s\n", zName, 19-nName, "", zValue);
1035
zName = X509_get_default_cert_dir_env();
1036
zValue = fossil_getenv(zName);
1037
if( zValue==0 ) zValue = "";
1038
trust_location_usable(zValue, &zUsed);
1039
nName = strlen(zName);
1040
fossil_print(" %s:%*s%s\n", zName, 19-nName, "", zValue);
1041
if( verbose ){
1042
fossil_print("\n"
1043
" Environment variables that determine alternative locations for\n"
1044
" the root certificates used by Fossil when it is acting as a SSL\n"
1045
" client. If specified, these alternative locations take top\n"
1046
" priority.\n\n"
1047
);
1048
}
1049
1050
zValue = db_get("ssl-ca-location","");
1051
trust_location_usable(zValue, &zUsed);
1052
fossil_print(" ssl-ca-location: %s\n", zValue);
1053
if( verbose ){
1054
fossil_print("\n"
1055
" This setting is the name of a file or directory that contains\n"
1056
" the complete set of root certificates used by Fossil when it\n"
1057
" is acting as a SSL client. If defined, this setting takes\n"
1058
" priority over built-in paths.\n\n"
1059
);
1060
}
1061
1062
1063
zValue = X509_get_default_cert_file();
1064
trust_location_usable(zValue, &zUsed);
1065
fossil_print(" OpenSSL-cert-file: %s\n", zValue);
1066
zValue = X509_get_default_cert_dir();
1067
trust_location_usable(zValue, &zUsed);
1068
fossil_print(" OpenSSL-cert-dir: %s\n", X509_get_default_cert_dir());
1069
if( verbose ){
1070
fossil_print("\n"
1071
" The default locations for the set of root certificates\n"
1072
" used by the \"fossil sync\" and similar commands to verify\n"
1073
" the identity of servers for \"https:\" URLs. These values\n"
1074
" come into play when Fossil is used as a TLS client. These\n"
1075
" values are built into your OpenSSL library.\n\n"
1076
);
1077
}
1078
1079
#if defined(_WIN32)
1080
fossil_print(" OpenSSL-winstore: %s\n",
1081
(SSLeay()>=0x30200000 && SSLeay()!=0x30500000) ? "Yes" : "No");
1082
if( verbose ){
1083
fossil_print("\n"
1084
" OpenSSL 3.2.0, or newer, but not version 3.5.0 due to a bug,\n"
1085
" are able to use the root certificates managed by the Windows\n"
1086
" operating system. The installed root certificates are listed\n"
1087
" by the command:\n\n"
1088
" certutil -store \"ROOT\"\n\n"
1089
);
1090
}
1091
#endif /* _WIN32 */
1092
1093
if( zUsed==0 ) zUsed = "";
1094
fossil_print(" Trust store used: %s\n", zUsed);
1095
if( verbose ){
1096
fossil_print("\n"
1097
" The location that is actually used for the root certificates\n"
1098
" used to verify the identity of servers for \"https:\" URLs.\n"
1099
" This will be one of the first of the five locations listed\n"
1100
" above that actually exists.\n\n"
1101
);
1102
}
1103
1104
1105
#endif /* FOSSIL_ENABLE_SSL */
1106
1107
1108
fossil_print("ssl-identity: %s\n", db_get("ssl-identity",""));
1109
if( verbose ){
1110
fossil_print("\n"
1111
" This setting is the name of a file that contains the PEM-format\n"
1112
" certificate and private-key used by Fossil clients to authenticate\n"
1113
" with servers. Few servers actually require this, so this setting\n"
1114
" is usually blank.\n\n"
1115
);
1116
}
1117
1118
db_prepare(&q,
1119
"SELECT name, '', value FROM global_config"
1120
" WHERE name GLOB 'cert:*'"
1121
"UNION ALL "
1122
"SELECT name, date(mtime,'unixepoch'), value FROM config"
1123
" WHERE name GLOB 'cert:*'"
1124
" ORDER BY name"
1125
);
1126
nHit = 0;
1127
while( db_step(&q)==SQLITE_ROW ){
1128
/* 123456789 123456789 123456789 */
1129
if( verbose ){
1130
fossil_print("exception: %-40s %s\n"
1131
" hash: %.57s\n",
1132
db_column_text(&q,0)+5, db_column_text(&q,1),
1133
db_column_text(&q,2));
1134
}else{
1135
fossil_print("exception: %-40s %s\n",
1136
db_column_text(&q,0)+5, db_column_text(&q,1));
1137
}
1138
nHit++;
1139
}
1140
db_finalize(&q);
1141
if( nHit && verbose ){
1142
fossil_print("\n"
1143
" The exceptions are server certificates that the Fossil client\n"
1144
" is unable to verify using root certificates, but which should be\n"
1145
" accepted anyhow.\n\n"
1146
);
1147
}
1148
1149
}else
1150
if( strncmp("remove-exception",zCmd,nCmd)==0 ){
1151
int i;
1152
Blob sql;
1153
char *zSep = "(";
1154
db_begin_transaction();
1155
blob_init(&sql, 0, 0);
1156
if( g.argc==4 && find_option("all",0,0)!=0 ){
1157
blob_append_sql(&sql,
1158
"DELETE FROM global_config WHERE name GLOB 'cert:*';\n"
1159
"DELETE FROM global_config WHERE name GLOB 'trusted:*';\n"
1160
"DELETE FROM config WHERE name GLOB 'cert:*';\n"
1161
"DELETE FROM config WHERE name GLOB 'trusted:*';\n"
1162
);
1163
}else{
1164
if( g.argc<4 ){
1165
usage("remove-exception DOMAIN-NAME ...");
1166
}
1167
blob_append_sql(&sql,"DELETE FROM global_config WHERE name IN ");
1168
for(i=3; i<g.argc; i++){
1169
blob_append_sql(&sql,"%s'cert:%q','trust:%q'",
1170
zSep/*safe-for-%s*/, g.argv[i], g.argv[i]);
1171
zSep = ",";
1172
}
1173
blob_append_sql(&sql,");\n");
1174
zSep = "(";
1175
blob_append_sql(&sql,"DELETE FROM config WHERE name IN ");
1176
for(i=3; i<g.argc; i++){
1177
blob_append_sql(&sql,"%s'cert:%q','trusted:%q'",
1178
zSep/*safe-for-%s*/, g.argv[i], g.argv[i]);
1179
zSep = ",";
1180
}
1181
blob_append_sql(&sql,");");
1182
}
1183
db_unprotect(PROTECT_CONFIG);
1184
db_exec_sql(blob_str(&sql));
1185
db_protect_pop();
1186
db_commit_transaction();
1187
blob_reset(&sql);
1188
}else
1189
/*default*/{
1190
fossil_fatal("unknown sub-command \"%s\".\nshould be one of:"
1191
" remove-exception scrub show",
1192
zCmd);
1193
}
1194
}
1195
1196
/*
1197
** WEBPAGE: .well-known
1198
**
1199
** If the "--acme" option was supplied to "fossil server" or "fossil http" or
1200
** similar, then this page returns the content of files found in the
1201
** ".well-known" subdirectory of the same directory that contains the
1202
** repository file. This facilitates Automated Certificate
1203
** Management using tools like "certbot".
1204
**
1205
** The content is returned directly, without any interpretation, using
1206
** a generic mimetype.
1207
*/
1208
void wellknown_page(void){
1209
char *zPath = 0;
1210
const char *zTail = P("name");
1211
Blob content;
1212
int i;
1213
char c;
1214
if( !g.fAllowACME ) goto wellknown_notfound;
1215
if( g.zRepositoryName==0 ) goto wellknown_notfound;
1216
if( zTail==0 ) goto wellknown_notfound;
1217
zPath = mprintf("%z/.well-known/%s", file_dirname(g.zRepositoryName), zTail);
1218
for(i=0; (c = zTail[i])!=0; i++){
1219
if( fossil_isalnum(c) ) continue;
1220
if( c=='.' ){
1221
if( i==0 || zTail[i-1]=='/' || zTail[i-1]=='.' ) goto wellknown_notfound;
1222
continue;
1223
}
1224
if( c==',' || c!='-' || c=='/' || c==':' || c=='_' || c=='~' ) continue;
1225
goto wellknown_notfound;
1226
}
1227
if( strstr("/..", zPath)!=0 ) goto wellknown_notfound;
1228
if( !file_isfile(zPath, ExtFILE) ) goto wellknown_notfound;
1229
blob_read_from_file(&content, zPath, ExtFILE);
1230
cgi_set_content(&content);
1231
cgi_set_content_type(mimetype_from_name(zPath));
1232
cgi_reply();
1233
return;
1234
1235
wellknown_notfound:
1236
fossil_free(zPath);
1237
webpage_notfound_error(0 /*works-like:""*/);
1238
return;
1239
}
1240
1241
/*
1242
** Return the OpenSSL version number being used. Space to hold
1243
** this name is obtained from fossil_malloc() and should be
1244
** freed by the caller.
1245
*/
1246
char *fossil_openssl_version(void){
1247
#if defined(FOSSIL_ENABLE_SSL)
1248
return mprintf("%s (0x%09x)\n",
1249
SSLeay_version(SSLEAY_VERSION), (sqlite3_uint64)SSLeay());
1250
#else
1251
return mprintf("none");
1252
#endif
1253
}
1254

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button