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