r7048: added auto-generation of TLS self-signed certificates if none exist already
authorAndrew Tridgell <tridge@samba.org>
Sat, 28 May 2005 03:50:13 +0000 (03:50 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:17:08 +0000 (13:17 -0500)
This allows smbd to be setup from scratch over ssl without having to
know how to create valid certificates (which can be quite tricky
unless you've done it before)

Of course, a good admin will provide real certificates, and smbd will
use them if specified

source/web_server/config.mk
source/web_server/tls.c
source/web_server/tlscert.c [new file with mode: 0644]

index 00ae2ea8a028ac889f1d625ac5ba1c4221567a61..49151299192619ce520e06d1e9855af2820ede17 100644 (file)
@@ -35,7 +35,8 @@ INIT_OBJ_FILES = \
 ADD_OBJ_FILES = \
                web_server/http.o \
                web_server/calls.o \
-               web_server/tls.o
+               web_server/tls.o \
+               web_server/tlscert.o
 REQUIRED_SUBSYSTEMS = ESP
 # End SUBSYSTEM WEB
 #######################
index 656c5ee6d66f3c3e7ba8f92ca81d29a50fa4dea7..13fc6e805b28af7cd97dd912da1b22d66eef8159 100644 (file)
@@ -240,17 +240,23 @@ void tls_initialise(struct task_server *task)
        tls = talloc_zero(edata, struct tls_data);
        edata->tls_data = tls;
 
+       if (!file_exist(cafile)) {
+               tls_cert_generate(tls, keyfile, certfile, cafile);
+       }
+
        ret = gnutls_global_init();
        if (ret < 0) goto init_failed;
 
        gnutls_certificate_allocate_credentials(&tls->x509_cred);
        if (ret < 0) goto init_failed;
 
-       ret = gnutls_certificate_set_x509_trust_file(tls->x509_cred, cafile, 
-                                                    GNUTLS_X509_FMT_PEM);      
-       if (ret < 0) {
-               DEBUG(0,("TLS failed to initialise cafile %s\n", cafile));
-               goto init_failed;
+       if (cafile && *cafile) {
+               ret = gnutls_certificate_set_x509_trust_file(tls->x509_cred, cafile, 
+                                                            GNUTLS_X509_FMT_PEM);      
+               if (ret < 0) {
+                       DEBUG(0,("TLS failed to initialise cafile %s\n", cafile));
+                       goto init_failed;
+               }
        }
 
        if (crlfile && *crlfile) {
@@ -258,7 +264,7 @@ void tls_initialise(struct task_server *task)
                                                           crlfile, 
                                                           GNUTLS_X509_FMT_PEM);
                if (ret < 0) {
-                       DEBUG(0,("TLS failed to initialise crlfile %s\n", cafile));
+                       DEBUG(0,("TLS failed to initialise crlfile %s\n", crlfile));
                        goto init_failed;
                }
        }
@@ -268,7 +274,7 @@ void tls_initialise(struct task_server *task)
                                                   GNUTLS_X509_FMT_PEM);
        if (ret < 0) {
                DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s\n", 
-                        lp_web_certfile(), lp_web_keyfile()));
+                        certfile, keyfile));
                goto init_failed;
        }
        
diff --git a/source/web_server/tlscert.c b/source/web_server/tlscert.c
new file mode 100644 (file)
index 0000000..81b2a0a
--- /dev/null
@@ -0,0 +1,149 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   auto-generate self signed TLS certificates
+
+   Copyright (C) Andrew Tridgell 2005
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+#if HAVE_LIBGNUTLS
+#include "gnutls/gnutls.h"
+#include "gnutls/x509.h"
+
+#define ORGANISATION_NAME "Samba Web Administration"
+#define UNIT_NAME         "SWAT - temporary autogenerated certificate"
+#define COMMON_NAME       "Samba SWAT"
+#define LIFETIME          700*24*60*60
+
+/* 
+   auto-generate a set of self signed certificates
+*/
+void tls_cert_generate(TALLOC_CTX *mem_ctx, 
+                      const char *keyfile, const char *certfile,
+                      const char *cafile)
+{
+       gnutls_x509_crt cacrt, crt;
+       gnutls_x509_privkey key, cakey;
+       uint32_t serial = (uint32_t)time(NULL);
+       char keyid[100];
+       char buf[4096];
+       size_t bufsize;
+       size_t keyidsize = sizeof(keyid);
+       time_t activation = time(NULL), expiry = activation + LIFETIME;
+       int ret;
+
+       if (file_exist(keyfile) || file_exist(certfile) || file_exist(cafile)) {
+               DEBUG(0,("TLS autogeneration skipped - some TLS files already exist\n"));
+               return;
+       }
+
+#define TLSCHECK(call) do { \
+       ret = call; \
+       if (ret < 0) { \
+               DEBUG(0,("TLS %s - %s\n", #call, gnutls_strerror(ret))); \
+               goto failed; \
+       } \
+} while (0)
+
+       TLSCHECK(gnutls_global_init());
+
+       DEBUG(0,("Attempting to autogenerate TLS self-signed keys for https\n"));
+       
+       DEBUG(3,("Generating private key\n"));
+       TLSCHECK(gnutls_x509_privkey_init(&key));
+       TLSCHECK(gnutls_x509_privkey_generate(key,   GNUTLS_PK_RSA, 1024, 0));
+
+       DEBUG(3,("Generating CA private key\n"));
+       TLSCHECK(gnutls_x509_privkey_init(&cakey));
+       TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, 1024, 0));
+
+       DEBUG(3,("Generating CA certificate\n"));
+       TLSCHECK(gnutls_x509_crt_init(&cacrt));
+       TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, 
+                                     GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
+                                     ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
+       TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, 
+                                     GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
+                                     UNIT_NAME, strlen(UNIT_NAME)));
+       TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
+                                     GNUTLS_OID_X520_COMMON_NAME, 0,
+                                     COMMON_NAME, strlen(COMMON_NAME)));
+       TLSCHECK(gnutls_x509_crt_set_key(cacrt, cakey));
+       TLSCHECK(gnutls_x509_crt_set_serial(cacrt, &serial, sizeof(serial)));
+       TLSCHECK(gnutls_x509_crt_set_activation_time(cacrt, activation));
+       TLSCHECK(gnutls_x509_crt_set_expiration_time(cacrt, expiry));
+       TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 0));
+       TLSCHECK(gnutls_x509_crt_set_key_purpose_oid(cacrt, GNUTLS_KP_TLS_WWW_SERVER, 0));
+       TLSCHECK(gnutls_x509_crt_set_version(cacrt, 3));
+       TLSCHECK(gnutls_x509_crt_get_key_id(cacrt, 0, keyid, &keyidsize));
+       TLSCHECK(gnutls_x509_crt_set_subject_key_id(cacrt, keyid, keyidsize));
+       TLSCHECK(gnutls_x509_crt_sign(cacrt, cacrt, cakey));
+
+       DEBUG(3,("Generating TLS certificate\n"));
+       TLSCHECK(gnutls_x509_crt_init(&crt));
+       TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, 
+                                     GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
+                                     ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
+       TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt, 
+                                     GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
+                                     UNIT_NAME, strlen(UNIT_NAME)));
+       TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt,
+                                     GNUTLS_OID_X520_COMMON_NAME, 0,
+                                     COMMON_NAME, strlen(COMMON_NAME)));
+       TLSCHECK(gnutls_x509_crt_set_key(crt, key));
+       TLSCHECK(gnutls_x509_crt_set_serial(crt, &serial, sizeof(serial)));
+       TLSCHECK(gnutls_x509_crt_set_activation_time(crt, activation));
+       TLSCHECK(gnutls_x509_crt_set_expiration_time(crt, expiry));
+       TLSCHECK(gnutls_x509_crt_set_ca_status(crt, 0));
+       TLSCHECK(gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0));
+       TLSCHECK(gnutls_x509_crt_set_version(crt, 3));
+       TLSCHECK(gnutls_x509_crt_get_key_id(crt, 0, keyid, &keyidsize));
+       TLSCHECK(gnutls_x509_crt_set_subject_key_id(crt, keyid, keyidsize));
+       TLSCHECK(gnutls_x509_crt_sign(crt, crt, key));
+
+       DEBUG(3,("Exporting TLS keys\n"));
+
+       bufsize = sizeof(buf);
+       TLSCHECK(gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buf, &bufsize));
+       file_save(certfile, buf, bufsize);
+
+       bufsize = sizeof(buf);
+       TLSCHECK(gnutls_x509_crt_export(cacrt, GNUTLS_X509_FMT_PEM, buf, &bufsize));
+       file_save(cafile, buf, bufsize);
+
+       bufsize = sizeof(buf);
+       TLSCHECK(gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &bufsize));
+       file_save(keyfile, buf, bufsize);
+
+       gnutls_x509_privkey_deinit(key);
+       gnutls_x509_privkey_deinit(cakey);
+       gnutls_x509_crt_deinit(cacrt);
+       gnutls_x509_crt_deinit(crt);
+       gnutls_global_deinit();
+
+       DEBUG(0,("TLS self-signed keys generated OK\n"));
+       return;
+
+failed:
+       DEBUG(0,("TLS certificate generation failed\n"));
+}
+
+#else
+ void tls_cert_dummy(void) {}
+#endif