Check-in [7532ffa4e3]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add a built-in self-signed certificate for use with TLS servers. Add --tls and --ssl options to active TLS for "fossil ui" and "fossil server". Add the "tls-server-cert" setting. Automatically start servers as TLS if the redirect-to-https property is 2.
Timelines: family | ancestors | descendants | both | ssl-server
Files: files | file ages | folders
SHA3-256: 7532ffa4e34e3174ae44e8e7b8567ad36f3e915c1d76666f92ebb48b397b4315
User & Date: drh 2021-12-27 12:49:00.148
Context
2021-12-27
16:13
Rename the "tls-config" command into "ssl-config" for consistency. The older "tls-config" command is retained as an alias. Enhance the command to support server certificate management. check-in: f6051784c5 user: drh tags: ssl-server
12:49
Add a built-in self-signed certificate for use with TLS servers. Add --tls and --ssl options to active TLS for "fossil ui" and "fossil server". Add the "tls-server-cert" setting. Automatically start servers as TLS if the redirect-to-https property is 2. check-in: 7532ffa4e3 user: drh tags: ssl-server
2021-12-26
21:50
Fix the build on Windows and on builds that omit OpenSSL. Improved error messages. check-in: 637516c447 user: drh tags: ssl-server
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/http_ssl.c.
53
54
55
56
57
58
59














































































































60
61
62
63
64
65
66
static SSL *ssl;
static struct {              /* Accept this SSL cert for this session only */
  char *zHost;                  /* Subject or host name */
  char *zHash;                  /* SHA2-256 hash of the cert */
} sException;
static int sslNoCertVerify = 0;  /* Do not verify SSL certs */















































































































/*
** Clear the SSL error message
*/
static void ssl_clear_errmsg(void){
  free(sslErrMsg);
  sslErrMsg = 0;
}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
static SSL *ssl;
static struct {              /* Accept this SSL cert for this session only */
  char *zHost;                  /* Subject or host name */
  char *zHash;                  /* SHA2-256 hash of the cert */
} sException;
static int sslNoCertVerify = 0;  /* Do not verify SSL certs */


/* This is a self-signed cert in the PEM format that can be used when
** no other certs are available.
*/
static const char sslSelfCert[] = 
"-----BEGIN CERTIFICATE-----\n"
"MIIDMTCCAhkCFGrDmuJkkzWERP/ITBvzwwI2lv0TMA0GCSqGSIb3DQEBCwUAMFQx\n"
"CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOQzESMBAGA1UEBwwJQ2hhcmxvdHRlMRMw\n"
"EQYDVQQKDApGb3NzaWwtU0NNMQ8wDQYDVQQDDAZGb3NzaWwwIBcNMjExMjI3MTEz\n"
"MTU2WhgPMjEyMTEyMjcxMTMxNTZaMFQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJO\n"
"QzESMBAGA1UEBwwJQ2hhcmxvdHRlMRMwEQYDVQQKDApGb3NzaWwtU0NNMQ8wDQYD\n"
"VQQDDAZGb3NzaWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCCbTU2\n"
"6GRQHQqLq7vyZ0OxpAxmgfAKCxt6eIz+jBi2ZM/CB5vVXWVh2+SkSiWEA3UZiUqX\n"
"xZlzmS/CglZdiwLLDJML8B4OiV72oivFH/vJ7+cbvh1dTxnYiHuww7GfQngPrLfe\n"
"fiIYPDk1GTUJHBQ7Ue477F7F8vKuHdVgwktF/JDM6M60aSqlo2D/oysirrb+dlur\n"
"Tlv0rjsYOfq6bLAajoL3qi/vek6DNssoywbge4PfbTgS9g7Gcgncbcet5pvaS12J\n"
"avhFcd4JU4Ity49Hl9S/C2MfZ1tE53xVggRwKz4FPj65M5uymTdcxtjKXtCxIE1k\n"
"KxJxXQh7rIYjm+RTAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFkdtpqcybAzJN8G\n"
"+ONuUm5sXNbWta7JGvm8l0BTSBcCUtJA3hn16iJqXA9KmLnaF2denC4EYk+KlVU1\n"
"QXxskPJ4jB8A5B05jMijYv0nzCxKhviI8CR7GLEEGKzeg9pbW0+O3vaVehoZtdFX\n"
"z3SsCssr9QjCLiApQxMzW1Iv3od2JXeHBwfVMFrWA1VCEUCRs8OSW/VOqDPJLVEi\n"
"G6wxc4kN9dLK+5S29q3nzl24/qzXoF8P9Re5KBCbrwaHgy+OEEceq5jkmfGFxXjw\n"
"pvVCNry5uAhH5NqbXZampUWqiWtM4eTaIPo7Y2mDA1uWhuWtO6F9PsnFJlQHCnwy\n"
"s/TsrXk=\n"
"-----END CERTIFICATE-----\n";

/* This is the private-key corresponding to the cert above
*/
static const char sslSelfPKey[] = 
"-----BEGIN PRIVATE KEY-----\n"
"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCCbTU26GRQHQqL\n"
"q7vyZ0OxpAxmgfAKCxt6eIz+jBi2ZM/CB5vVXWVh2+SkSiWEA3UZiUqXxZlzmS/C\n"
"glZdiwLLDJML8B4OiV72oivFH/vJ7+cbvh1dTxnYiHuww7GfQngPrLfefiIYPDk1\n"
"GTUJHBQ7Ue477F7F8vKuHdVgwktF/JDM6M60aSqlo2D/oysirrb+dlurTlv0rjsY\n"
"Ofq6bLAajoL3qi/vek6DNssoywbge4PfbTgS9g7Gcgncbcet5pvaS12JavhFcd4J\n"
"U4Ity49Hl9S/C2MfZ1tE53xVggRwKz4FPj65M5uymTdcxtjKXtCxIE1kKxJxXQh7\n"
"rIYjm+RTAgMBAAECggEANfTH1vc8yIe7HRzmm9lsf8jF+II4s2705y2H5qY+cvYx\n"
"nKtZJGOG1X0KkYy7CGoFv5K0cSUl3lS5FVamM/yWIzoIex/Sz2C1EIL2aI5as6ez\n"
"jB6SN0/J+XI8+Vt7186/rHxfdIPpxuzjHbxX3HTpScETNWcLrghbrPxakbTPPxwt\n"
"+x7QlPmmkFNuMfvkzToFf9NdwL++44TeBPOpvD/Lrw+eyqdth9RJPq9cM96plh9V\n"
"HuRqeD8+QNafaXBdSQs3FJK/cDK/vWGKZWIfFVSDbDhwYljkXGijreFjtXQfkkpF\n"
"rl1J87/H9Ee7z8fTD2YXQHl+0/rghAVtac3u54dpQQKBgQC2XG3OEeMrOp9dNkUd\n"
"F8VffUg0ecwG+9L3LCe7U71K0kPmXjV6xNnuYcNQu84kptc5vI8wD23p29LaxdNc\n"
"9m0lcw06/YYBOPkNphcHkINYZTvVJF10mL3isymzMaTtwDkZUkOjL1B+MTiFT/qp\n"
"ARKrTYGJ4HxY7+tUkI5pUmg4PQKBgQC3GA4d1Rz3Pb/RRpcsZgWknKsKhoN36mSn\n"
"xFJ3wPBvVv2B1ltTMzh/+the0ty6clzMrvoLERzRcheDsNrc/j/TUVG8sVdBYJwX\n"
"tMZyFW4NVMOErT/1ukh6jBqIMBo6NJL3EV/AKj0yniksgKOr0/AAduAccnGST8Jd\n"
"SHOdjwvHzwKBgGZBq/zqgNTDuYseHGE07CMgcDWkumiMGv8ozlq3mSR0hUiPOTPP\n"
"YFjQjyIdPXnF6FfiyPPtIvgIoNK2LVAqiod+XUPf152l4dnqcW13dn9BvOxGyPTR\n"
"lWCikFaAFviOWjY9r9m4dU1dslDmySqthFd0TZgPvgps9ivkJ0cdw30NAoGAMC/E\n"
"h1VvKiK2OP27C5ROJ+STn1GHiCfIFd81VQ8SODtMvL8NifgRBp2eFFaqgOdYRQZI\n"
"CGGYlAbS6XXCJCdF5Peh62dA75PdgN+y2pOJQzjrvB9cle9Q4++7i9wdCvSLOTr5\n"
"WDnFoWy+qVexu6crovOmR9ZWzYrwPFy1EOJ010ECgYBl7Q+jmjOSqsVwhFZ0U7LG\n"
"diN+vXhWfn1wfOWd8u79oaqU/Oy7xyKW2p3H5z2KFrBM/vib53Lh4EwFZjcX+jVG\n"
"krAmbL+M/hP7z3TD2UbESAzR/c6l7FU45xN84Lsz5npkR8H/uAHuqLgb9e430Mjx\n"
"YNMwdb8rChHHChNZu6zuxw==\n"
"-----END PRIVATE KEY-----\n";

/*
** Read a PEM certificate from memory and push it into an SSL_CTX.
** Return the number of errors.
*/
static int sslctx_use_cert_from_mem(
  SSL_CTX *ctx,
  const char *pData,
  int nData
){
  BIO *in;
  int rc = 1;
  X509 *x = 0;
  X509 *cert = 0;

  in = BIO_new_mem_buf(pData, nData);
  if( in==0 ) goto end_of_ucfm;
  // x = X509_new_ex(ctx->libctx, ctx->propq);
  x = X509_new();
  if( x==0 ) goto end_of_ucfm;
  cert = PEM_read_bio_X509(in, &x, 0, 0);
  if( cert==0 ) goto end_of_ucfm;
  rc = SSL_CTX_use_certificate(ctx, x)<=0;
end_of_ucfm:
  X509_free(x);
  BIO_free(in);
  return rc;
}

/*
** Read a PEM private key from memory and add it to an SSL_CTX.
** Return the number of errors.
*/
static int sslctx_use_pkey_from_mem(
  SSL_CTX *ctx,
  const char *pData,
  int nData
){
  int rc = 1;
  BIO *in;
  EVP_PKEY *pkey = 0;

  in = BIO_new_mem_buf(pData, nData);
  if( in==0 ) goto end_of_upkfm;
  pkey = PEM_read_bio_PrivateKey(in, 0, 0, 0);
  if( pkey==0 ) goto end_of_upkfm;
  rc = SSL_CTX_use_PrivateKey(ctx, pkey)<=0;
  EVP_PKEY_free(pkey);
end_of_upkfm:
  BIO_free(in);
  return rc;
}

/*
** Clear the SSL error message
*/
static void ssl_clear_errmsg(void){
  free(sslErrMsg);
  sslErrMsg = 0;
}
579
580
581
582
583
584
585



586
587





588
589
590

591
592
593
594
595
596
597
598

599
600
601
602
603
604
605
606












607
608
609
610
611
612
613
}

/*
** Initialize the SSL library so that it is able to handle
** server-side connections.  Invoke fossil_fatal() if there are
** any problems.
**



** zKeyFile may be NULL, in which case zCertFile will contain both
** the private key and the cert.





*/
void ssl_init_server(const char *zCertFile, const char *zKeyFile){
  if( sslIsInit==0 ){

    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
    sslCtx = SSL_CTX_new(SSLv23_server_method());
    if( sslCtx==0 ){
      ERR_print_errors_fp(stderr);
      fossil_fatal("Error initializing the SSL server");
    }

    if( SSL_CTX_use_certificate_file(sslCtx, zCertFile, SSL_FILETYPE_PEM)<=0 ){
      ERR_print_errors_fp(stderr);
      fossil_fatal("Error loading CERT file \"%s\"", zCertFile);
    }
    if( zKeyFile==0 ) zKeyFile = zCertFile;
    if( SSL_CTX_use_PrivateKey_file(sslCtx, zKeyFile, SSL_FILETYPE_PEM)<=0 ){
      ERR_print_errors_fp(stderr);
      fossil_fatal("Error loading PRIVATE KEY from file \"%s\"", zKeyFile);












    }
    if( !SSL_CTX_check_private_key(sslCtx) ){
      fossil_fatal("PRIVATE KEY \"%s\" does not match CERT \"%s\"",
           zKeyFile, zCertFile);
    }
    sslIsInit = 2;
  }else{







>
>
>
|
|
>
>
>
>
>



>








>
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>







689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
}

/*
** Initialize the SSL library so that it is able to handle
** server-side connections.  Invoke fossil_fatal() if there are
** any problems.
**
** If zKeyFile and zCertFile are not NULL, then they are the names
** of disk files that hold the certificate and private-key for the
** server.  If zCertFile is not NULL but zKeyFile is NULL, then
** zCertFile is assumed to be a concatenation of the certificate and
** the private-key in the PEM format.
**
** If zCertFile is NULL, then "tls-server-cert" setting is consulted
** to get the certificate and private-key (concatenated together, in
** the PEM format).  If there is no tls-server-cert setting, then
** a built-in self-signed cert is used.
*/
void ssl_init_server(const char *zCertFile, const char *zKeyFile){
  if( sslIsInit==0 ){
    const char *zTlsCert;
    SSL_library_init();
    SSL_load_error_strings();
    OpenSSL_add_all_algorithms();
    sslCtx = SSL_CTX_new(SSLv23_server_method());
    if( sslCtx==0 ){
      ERR_print_errors_fp(stderr);
      fossil_fatal("Error initializing the SSL server");
    }
    if( zCertFile && zCertFile[0] ){
      if( SSL_CTX_use_certificate_file(sslCtx,zCertFile,SSL_FILETYPE_PEM)<=0 ){
        ERR_print_errors_fp(stderr);
        fossil_fatal("Error loading CERT file \"%s\"", zCertFile);
      }
      if( zKeyFile==0 ) zKeyFile = zCertFile;
      if( SSL_CTX_use_PrivateKey_file(sslCtx, zKeyFile, SSL_FILETYPE_PEM)<=0 ){
        ERR_print_errors_fp(stderr);
        fossil_fatal("Error loading PRIVATE KEY from file \"%s\"", zKeyFile);
      }
    }else
    if( (zTlsCert = db_get("tls-server-cert",0))!=0 ){
      if( sslctx_use_cert_from_mem(sslCtx, zTlsCert, -1)
       || sslctx_use_pkey_from_mem(sslCtx, zTlsCert, -1)
      ){
        fossil_fatal("Error loading the CERT from the"
                     " 'tls-server-cert' setting");
      }
    }else if( sslctx_use_cert_from_mem(sslCtx, sslSelfCert, -1)
           || sslctx_use_pkey_from_mem(sslCtx, sslSelfPKey, -1) ){
      fossil_fatal("Error loading self-signed CERT");
    }
    if( !SSL_CTX_check_private_key(sslCtx) ){
      fossil_fatal("PRIVATE KEY \"%s\" does not match CERT \"%s\"",
           zKeyFile, zCertFile);
    }
    sslIsInit = 2;
  }else{
Changes to src/main.c.
2846
2847
2848
2849
2850
2851
2852










2853
2854
2855
2856
2857
2858
2859
#if FOSSIL_ENABLE_SSL
  const char *zCertFile = 0;
  zCertFile = find_option("tls-cert-file",0,1);
  if( zCertFile ){
    g.httpUseSSL = 1;
    ssl_init_server(zCertFile, zCertFile);
  }










#endif
}

/*
** COMMAND: server*
** COMMAND: ui
**







>
>
>
>
>
>
>
>
>
>







2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
#if FOSSIL_ENABLE_SSL
  const char *zCertFile = 0;
  zCertFile = find_option("tls-cert-file",0,1);
  if( zCertFile ){
    g.httpUseSSL = 1;
    ssl_init_server(zCertFile, zCertFile);
  }
  if( find_option("tls",0,0)!=0 || find_option("ssl",0,0)!=0 ){
    g.httpUseSSL = 1;
    ssl_init_server(0,0);
  }
#if !defined(_WIN32)
  if( db_get_int("redirect-to-https",0)==2 ){
    g.httpUseSSL = 1;
    ssl_init_server(0,0);
  }
#endif
#endif
}

/*
** COMMAND: server*
** COMMAND: ui
**
2946
2947
2948
2949
2950
2951
2952

2953


2954
2955
2956
2957
2958
2959
2960
**                       set by default for the "ui" command)
**   --notfound URL      Redirect
**   --page PAGE         Start "ui" on PAGE.  ex: --page "timeline?y=ci"
**   -P|--port TCPPORT   listen to request on port TCPPORT
**   --repolist          If REPOSITORY is dir, URL "/" lists repos.
**   --scgi              Accept SCGI rather than HTTP
**   --skin LABEL        Use override skin LABEL

**   --th-trace          trace TH1 execution (for debugging purposes)


**   --usepidkey         Use saved encryption key from parent process.  This is
**                       only necessary when using SEE on Windows.
**
** See also: [[cgi]], [[http]], [[winsrv]]
*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */







>

>
>







2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
**                       set by default for the "ui" command)
**   --notfound URL      Redirect
**   --page PAGE         Start "ui" on PAGE.  ex: --page "timeline?y=ci"
**   -P|--port TCPPORT   listen to request on port TCPPORT
**   --repolist          If REPOSITORY is dir, URL "/" lists repos.
**   --scgi              Accept SCGI rather than HTTP
**   --skin LABEL        Use override skin LABEL
**   --ssl               Use TLS (HTTPS) encryption.  Alias for --tls
**   --th-trace          trace TH1 execution (for debugging purposes)
**   --tls               Use TLS (HTTPS) encryption.
**   --tls-cert-file FN  Read the TLS certificate and private key from FN
**   --usepidkey         Use saved encryption key from parent process.  This is
**                       only necessary when using SEE on Windows.
**
** See also: [[cgi]], [[http]], [[winsrv]]
*/
void cmd_webserver(void){
  int iPort, mxPort;        /* Range of TCP ports allowed */