1 /*
2    auto-generate self signed TLS certificates. Imported from Samba.
3 
4    Copyright (C) Andrew Tridgell 2005
5    Copyright (C) Jelmer Vernooij 2006-2007
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #include "ctrlproxy.h"
23 
24 #include <glib.h>
25 
26 #include "ssl.h"
27 
28 #include <gnutls/gnutls.h>
29 #include <gnutls/x509.h>
30 
31 #define ORGANISATION_NAME "CtrlProxy"
32 #define UNIT_NAME         "CtrlProxy - temporary autogenerated certificate"
33 #define COMMON_NAME       "CtrlProxy"
34 #define LIFETIME          700*24*60*60
35 #define DH_BITS 		  1024
36 
37 /*
38    auto-generate a set of self signed certificates
39 */
ssl_cert_generate(const char * keyfile,const char * certfile,const char * cafile)40 void ssl_cert_generate(const char *keyfile, const char *certfile,
41 		       const char *cafile)
42 {
43 	gnutls_x509_crt cacrt, crt;
44 	gnutls_x509_privkey key, cakey;
45 	guint32 serial = (guint32)time(NULL);
46 	unsigned char keyid[100];
47 	char buf[4096];
48 	size_t bufsize;
49 	size_t keyidsize = sizeof(keyid);
50 	time_t activation = time(NULL), expiry = activation + LIFETIME;
51 	int ret;
52 
53 	if (g_file_test(keyfile, G_FILE_TEST_EXISTS) ||
54 		g_file_test(certfile, G_FILE_TEST_EXISTS) ||
55 		g_file_test(cafile, G_FILE_TEST_EXISTS)) {
56 		log_global(LOG_WARNING, "TLS autogeneration skipped - some TLS files already exist");
57 		return;
58 	}
59 
60 #define TLSCHECK(call) do { \
61 	ret = call; \
62 	if (ret < 0) { \
63 		log_global(LOG_WARNING, "TLS %s - %s", #call, gnutls_strerror(ret)); \
64 		goto failed; \
65 	} \
66 } while (0)
67 
68 	TLSCHECK(gnutls_global_init());
69 
70 	log_global(LOG_INFO,
71 			   "Attempting to autogenerate TLS self-signed keys");
72 
73 	log_global(LOG_TRACE, "Generating private key");
74 	TLSCHECK(gnutls_x509_privkey_init(&key));
75 	TLSCHECK(gnutls_x509_privkey_generate(key,   GNUTLS_PK_RSA, DH_BITS, 0));
76 
77 	log_global(LOG_TRACE, "Generating CA private key");
78 	TLSCHECK(gnutls_x509_privkey_init(&cakey));
79 	TLSCHECK(gnutls_x509_privkey_generate(cakey, GNUTLS_PK_RSA, DH_BITS, 0));
80 
81 	log_global(LOG_TRACE, "Generating CA certificate");
82 	TLSCHECK(gnutls_x509_crt_init(&cacrt));
83 	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
84 				      GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
85 				      ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
86 	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
87 				      GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
88 				      UNIT_NAME, strlen(UNIT_NAME)));
89 	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(cacrt,
90 				      GNUTLS_OID_X520_COMMON_NAME, 0,
91 				      COMMON_NAME, strlen(COMMON_NAME)));
92 	TLSCHECK(gnutls_x509_crt_set_key(cacrt, cakey));
93 	TLSCHECK(gnutls_x509_crt_set_serial(cacrt, &serial, sizeof(serial)));
94 	TLSCHECK(gnutls_x509_crt_set_activation_time(cacrt, activation));
95 	TLSCHECK(gnutls_x509_crt_set_expiration_time(cacrt, expiry));
96 	TLSCHECK(gnutls_x509_crt_set_ca_status(cacrt, 0));
97 	TLSCHECK(gnutls_x509_crt_set_version(cacrt, 3));
98 	TLSCHECK(gnutls_x509_crt_get_key_id(cacrt, 0, keyid, &keyidsize));
99 	TLSCHECK(gnutls_x509_crt_set_subject_key_id(cacrt, keyid, keyidsize));
100 	TLSCHECK(gnutls_x509_crt_sign(cacrt, cacrt, cakey));
101 
102 	log_global(LOG_TRACE, "Generating TLS certificaten");
103 	TLSCHECK(gnutls_x509_crt_init(&crt));
104 	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt,
105 				      GNUTLS_OID_X520_ORGANIZATION_NAME, 0,
106 				      ORGANISATION_NAME, strlen(ORGANISATION_NAME)));
107 	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt,
108 				      GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, 0,
109 				      UNIT_NAME, strlen(UNIT_NAME)));
110 	TLSCHECK(gnutls_x509_crt_set_dn_by_oid(crt,
111 				      GNUTLS_OID_X520_COMMON_NAME, 0,
112 				      COMMON_NAME, strlen(COMMON_NAME)));
113 	TLSCHECK(gnutls_x509_crt_set_key(crt, key));
114 	TLSCHECK(gnutls_x509_crt_set_serial(crt, &serial, sizeof(serial)));
115 	TLSCHECK(gnutls_x509_crt_set_activation_time(crt, activation));
116 	TLSCHECK(gnutls_x509_crt_set_expiration_time(crt, expiry));
117 	TLSCHECK(gnutls_x509_crt_set_ca_status(crt, 0));
118 	TLSCHECK(gnutls_x509_crt_set_version(crt, 3));
119 	TLSCHECK(gnutls_x509_crt_get_key_id(crt, 0, keyid, &keyidsize));
120 	TLSCHECK(gnutls_x509_crt_set_subject_key_id(crt, keyid, keyidsize));
121 	TLSCHECK(gnutls_x509_crt_sign(crt, crt, key));
122 
123 	log_global(LOG_TRACE, "Exporting TLS keys");
124 
125 	bufsize = sizeof(buf);
126 	TLSCHECK(gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, buf, &bufsize));
127 	g_file_set_contents(certfile, buf, bufsize, NULL);
128 
129 	bufsize = sizeof(buf);
130 	TLSCHECK(gnutls_x509_crt_export(cacrt, GNUTLS_X509_FMT_PEM, buf, &bufsize));
131 	g_file_set_contents(cafile, buf, bufsize, NULL);
132 
133 	bufsize = sizeof(buf);
134 	TLSCHECK(gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &bufsize));
135 	g_file_set_contents(keyfile, buf, bufsize, NULL);
136 
137 	gnutls_x509_privkey_deinit(key);
138 	gnutls_x509_privkey_deinit(cakey);
139 	gnutls_x509_crt_deinit(cacrt);
140 	gnutls_x509_crt_deinit(crt);
141 
142 	log_global(LOG_INFO, "TLS self-signed keys generated OK");
143 	return;
144 
145 failed:
146 	log_global(LOG_WARNING, "TLS certificate generation failed");
147 }
148 
ssl_create_server_credentials(const char * config_dir,GKeyFile * kf,const char * group)149 gpointer ssl_create_server_credentials(const char *config_dir,
150 									   GKeyFile *kf, const char *group)
151 {
152 	if (!g_key_file_has_key(kf, group, "keyfile", NULL) &&
153 		!g_key_file_has_key(kf, group, "certfile", NULL)) {
154 		char *keyfile = g_build_filename(config_dir, "key.pem", NULL);
155 		char *certfile = g_build_filename(config_dir, "cert.pem", NULL);
156 		g_key_file_set_string(kf, group, "keyfile", keyfile);
157 		g_key_file_set_string(kf, group, "certfile", certfile);
158 		if (!g_file_test(keyfile, G_FILE_TEST_EXISTS) &&
159 			!g_file_test(certfile, G_FILE_TEST_EXISTS)) {
160 			char *cafile = g_build_filename(config_dir, "ca.pem", NULL);
161 			ssl_cert_generate(keyfile, certfile, cafile);
162 			g_free(cafile);
163 		}
164 		g_free(keyfile);
165 		g_free(certfile);
166 	}
167 
168 	return ssl_get_server_credentials(
169 					g_key_file_get_string(kf, group, "certfile", NULL),
170 					g_key_file_get_string(kf, group, "keyfile", NULL));
171 }
172