cae8358eda088391818e970eae4b1329eaa4fc94
[jelmer/ctrlproxy.git] / src / tlscert.c
1 /* 
2    auto-generate self signed TLS certificates. Imported from Samba.
3
4    Copyright (C) Andrew Tridgell 2005
5    Copyright (C) Jelmer Vernooij 2006
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 2 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 */
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
149 gpointer ssl_create_server_credentials(struct global *global, 
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(global->config->config_dir, "key.pem", NULL);
155                 char *certfile = g_build_filename(global->config->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(global->config->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 }