diff options
Diffstat (limited to 'source4/lib/tls/tlscert.c')
-rw-r--r-- | source4/lib/tls/tlscert.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/source4/lib/tls/tlscert.c b/source4/lib/tls/tlscert.c new file mode 100644 index 0000000..36482e3 --- /dev/null +++ b/source4/lib/tls/tlscert.c @@ -0,0 +1,159 @@ +/* + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "lib/tls/tls.h" + +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> + +#define ORGANISATION_NAME "Samba Administration" +#define CA_NAME "Samba - temporary autogenerated CA certificate" +#define UNIT_NAME "Samba - temporary autogenerated HOST certificate" +#define LIFETIME 700*24*60*60 + +/* FIPS140-2 only allows 2048 or 3072 prime sizes. */ +#define RSA_BITS gnutls_fips140_mode_enabled() ? 3072 : 4096 + +/* + auto-generate a set of self signed certificates +*/ +void tls_cert_generate(TALLOC_CTX *mem_ctx, + const char *hostname, + const char *keyfile, const char *certfile, + const char *cafile) +{ + gnutls_x509_crt_t cacrt, crt; + gnutls_x509_privkey_t key, cakey; + uint32_t serial = (uint32_t)time(NULL); + unsigned 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) + + DEBUG(0,("Attempting to autogenerate TLS self-signed keys for https for hostname '%s'\n", + hostname)); + + DEBUG(3,("Generating private key\n")); + TLSCHECK(gnutls_x509_privkey_init(&key)); + TLSCHECK(gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, RSA_BITS, 0)); + + DEBUG(3,("Generating CA private key\n")); + TLSCHECK(gnutls_x509_privkey_init(&cakey)); + TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, RSA_BITS, 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, + CA_NAME, strlen(CA_NAME))); + TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt, + GNUTLS_OID_X520_COMMON_NAME, 0, + hostname, strlen(hostname))); + 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, 1)); + TLSCHECK(gnutls_x509_crt_set_key_usage(cacrt, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN)); + 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_sign2(cacrt, cacrt, cakey, + GNUTLS_DIG_SHA256, 0)); + + 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, + hostname, strlen(hostname))); + 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_sign2(crt, crt, key, + GNUTLS_DIG_SHA256, 0)); + TLSCHECK(gnutls_x509_crt_sign2(crt, cacrt, cakey, + GNUTLS_DIG_SHA256, 0)); + + DEBUG(3,("Exporting TLS keys\n")); + + bufsize = sizeof(buf); + TLSCHECK(gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buf, &bufsize)); + if (!file_save(certfile, buf, bufsize)) { + DEBUG(0,("Unable to save certificate in %s parent dir exists ?\n", certfile)); + goto failed; + } + + bufsize = sizeof(buf); + TLSCHECK(gnutls_x509_crt_export(cacrt, GNUTLS_X509_FMT_PEM, buf, &bufsize)); + if (!file_save(cafile, buf, bufsize)) { + DEBUG(0,("Unable to save ca cert in %s parent dir exists ?\n", cafile)); + goto failed; + } + + bufsize = sizeof(buf); + TLSCHECK(gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &bufsize)); + if (!file_save_mode(keyfile, buf, bufsize, 0600)) { + DEBUG(0,("Unable to save privatekey in %s parent dir exists ?\n", keyfile)); + goto failed; + } + + gnutls_x509_privkey_deinit(key); + gnutls_x509_privkey_deinit(cakey); + gnutls_x509_crt_deinit(cacrt); + gnutls_x509_crt_deinit(crt); + + DEBUG(0,("TLS self-signed keys generated OK\n")); + return; + +failed: + DEBUG(0,("TLS certificate generation failed\n")); +} |