]>
Commit | Line | Data |
---|---|---|
82cc1f9a | 1 | /* |
a51f28ec | 2 | * "$Id: tls-gnutls.c 11899 2014-05-27 15:10:09Z msweet $" |
82cc1f9a MS |
3 | * |
4 | * TLS support code for the CUPS scheduler using GNU TLS. | |
5 | * | |
6 | * Copyright 2007-2012 by Apple Inc. | |
7 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. | |
8 | * | |
9 | * These coded instructions, statements, and computer programs are the | |
10 | * property of Apple Inc. and are protected by Federal copyright | |
11 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
12 | * which should have been included with this file. If this file is | |
13 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
14 | * | |
15 | * Contents: | |
16 | * | |
17 | * cupsdEndTLS() - Shutdown a secure session with the client. | |
18 | * cupsdStartTLS() - Start a secure session with the client. | |
19 | * make_certificate() - Make a self-signed SSL/TLS certificate. | |
20 | */ | |
21 | ||
22 | ||
23 | /* | |
24 | * Local functions... | |
25 | */ | |
26 | ||
27 | static int make_certificate(cupsd_client_t *con); | |
28 | ||
29 | ||
30 | /* | |
31 | * 'cupsdEndTLS()' - Shutdown a secure session with the client. | |
32 | */ | |
33 | ||
34 | int /* O - 1 on success, 0 on error */ | |
35 | cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ | |
36 | { | |
37 | int error; /* Error code */ | |
38 | gnutls_certificate_server_credentials *credentials; | |
39 | /* TLS credentials */ | |
40 | ||
41 | ||
42 | credentials = (gnutls_certificate_server_credentials *) | |
43 | (con->http.tls_credentials); | |
44 | ||
45 | error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR); | |
46 | switch (error) | |
47 | { | |
48 | case GNUTLS_E_SUCCESS: | |
49 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
50 | "SSL shutdown successful!"); | |
51 | break; | |
52 | default: | |
53 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
54 | "SSL shutdown failed: %s", gnutls_strerror(error)); | |
55 | break; | |
56 | } | |
57 | ||
58 | gnutls_deinit(con->http.tls); | |
59 | con->http.tls = NULL; | |
60 | ||
61 | gnutls_certificate_free_credentials(*credentials); | |
62 | free(credentials); | |
63 | ||
64 | return (1); | |
65 | } | |
66 | ||
67 | ||
68 | /* | |
69 | * 'cupsdStartTLS()' - Start a secure session with the client. | |
70 | */ | |
71 | ||
72 | int /* O - 1 on success, 0 on error */ | |
73 | cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ | |
74 | { | |
75 | int status; /* Error code */ | |
76 | gnutls_certificate_server_credentials *credentials; | |
77 | /* TLS credentials */ | |
78 | ||
79 | ||
80 | cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", | |
81 | con->http.fd); | |
82 | ||
83 | /* | |
84 | * Verify that we have a certificate... | |
85 | */ | |
86 | ||
87 | if (access(ServerKey, 0) || access(ServerCertificate, 0)) | |
88 | { | |
89 | /* | |
90 | * Nope, make a self-signed certificate... | |
91 | */ | |
92 | ||
93 | if (!make_certificate(con)) | |
94 | return (0); | |
95 | } | |
96 | ||
97 | /* | |
98 | * Create the SSL object and perform the SSL handshake... | |
99 | */ | |
100 | ||
101 | credentials = (gnutls_certificate_server_credentials *) | |
102 | malloc(sizeof(gnutls_certificate_server_credentials)); | |
103 | if (credentials == NULL) | |
104 | { | |
105 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
106 | "Unable to encrypt connection from %s - %s", | |
107 | con->http.hostname, strerror(errno)); | |
108 | ||
109 | return (0); | |
110 | } | |
111 | ||
112 | gnutls_certificate_allocate_credentials(credentials); | |
113 | gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, | |
114 | ServerKey, GNUTLS_X509_FMT_PEM); | |
115 | ||
116 | gnutls_init(&con->http.tls, GNUTLS_SERVER); | |
117 | gnutls_set_default_priority(con->http.tls); | |
118 | ||
119 | gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials); | |
a51f28ec | 120 | gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr_t)HTTP(con)); |
82cc1f9a MS |
121 | gnutls_transport_set_pull_function(con->http.tls, _httpReadGNUTLS); |
122 | gnutls_transport_set_push_function(con->http.tls, _httpWriteGNUTLS); | |
123 | ||
124 | while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS) | |
125 | { | |
126 | if (gnutls_error_is_fatal(status)) | |
127 | { | |
128 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
129 | "Unable to encrypt connection from %s - %s", | |
130 | con->http.hostname, gnutls_strerror(status)); | |
131 | ||
132 | gnutls_deinit(con->http.tls); | |
133 | gnutls_certificate_free_credentials(*credentials); | |
134 | con->http.tls = NULL; | |
135 | free(credentials); | |
136 | return (0); | |
137 | } | |
138 | } | |
139 | ||
140 | cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", | |
141 | con->http.hostname); | |
142 | ||
143 | con->http.tls_credentials = credentials; | |
144 | return (1); | |
145 | } | |
146 | ||
147 | ||
148 | /* | |
149 | * 'make_certificate()' - Make a self-signed SSL/TLS certificate. | |
150 | */ | |
151 | ||
152 | static int /* O - 1 on success, 0 on failure */ | |
153 | make_certificate(cupsd_client_t *con) /* I - Client connection */ | |
154 | { | |
a51f28ec MS |
155 | gnutls_x509_crt_t crt; /* Self-signed certificate */ |
156 | gnutls_x509_privkey_t key; /* Encryption key */ | |
82cc1f9a MS |
157 | cups_lang_t *language; /* Default language info */ |
158 | cups_file_t *fp; /* Key/cert file */ | |
159 | unsigned char buffer[8192]; /* Buffer for x509 data */ | |
160 | size_t bytes; /* Number of bytes of data */ | |
161 | unsigned char serial[4]; /* Serial number buffer */ | |
162 | time_t curtime; /* Current time */ | |
163 | int result; /* Result of GNU TLS calls */ | |
164 | ||
165 | ||
166 | /* | |
167 | * Create the encryption key... | |
168 | */ | |
169 | ||
170 | cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key..."); | |
171 | ||
172 | gnutls_x509_privkey_init(&key); | |
173 | gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); | |
174 | ||
175 | /* | |
176 | * Save it... | |
177 | */ | |
178 | ||
179 | bytes = sizeof(buffer); | |
180 | ||
181 | if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, | |
182 | buffer, &bytes)) < 0) | |
183 | { | |
184 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s", | |
185 | gnutls_strerror(result)); | |
186 | gnutls_x509_privkey_deinit(key); | |
187 | return (0); | |
188 | } | |
189 | else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL) | |
190 | { | |
191 | cupsFileWrite(fp, (char *)buffer, bytes); | |
192 | cupsFileClose(fp); | |
193 | ||
194 | cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", | |
195 | ServerKey); | |
196 | } | |
197 | else | |
198 | { | |
199 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
200 | "Unable to create SSL server key file \"%s\" - %s", | |
201 | ServerKey, strerror(errno)); | |
202 | gnutls_x509_privkey_deinit(key); | |
203 | return (0); | |
204 | } | |
205 | ||
206 | /* | |
207 | * Create the self-signed certificate... | |
208 | */ | |
209 | ||
210 | cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate..."); | |
211 | ||
212 | language = cupsLangDefault(); | |
213 | curtime = time(NULL); | |
214 | serial[0] = curtime >> 24; | |
215 | serial[1] = curtime >> 16; | |
216 | serial[2] = curtime >> 8; | |
217 | serial[3] = curtime; | |
218 | ||
219 | gnutls_x509_crt_init(&crt); | |
220 | if (strlen(language->language) == 5) | |
221 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, | |
222 | language->language + 3, 2); | |
223 | else | |
224 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, | |
225 | "US", 2); | |
226 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, | |
227 | ServerName, strlen(ServerName)); | |
228 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, | |
229 | ServerName, strlen(ServerName)); | |
230 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, | |
231 | 0, "Unknown", 7); | |
232 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, | |
233 | "Unknown", 7); | |
234 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, | |
235 | "Unknown", 7); | |
236 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, | |
237 | ServerAdmin, strlen(ServerAdmin)); | |
238 | gnutls_x509_crt_set_key(crt, key); | |
239 | gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); | |
240 | gnutls_x509_crt_set_activation_time(crt, curtime); | |
241 | gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); | |
242 | gnutls_x509_crt_set_ca_status(crt, 0); | |
243 | gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, | |
244 | ServerName); | |
245 | gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); | |
246 | gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); | |
247 | gnutls_x509_crt_set_version(crt, 3); | |
248 | ||
249 | bytes = sizeof(buffer); | |
250 | if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) | |
251 | gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); | |
252 | ||
253 | gnutls_x509_crt_sign(crt, crt, key); | |
254 | ||
255 | /* | |
256 | * Save it... | |
257 | */ | |
258 | ||
259 | bytes = sizeof(buffer); | |
260 | if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, | |
261 | buffer, &bytes)) < 0) | |
262 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
263 | "Unable to export SSL server certificate - %s", | |
264 | gnutls_strerror(result)); | |
265 | else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL) | |
266 | { | |
267 | cupsFileWrite(fp, (char *)buffer, bytes); | |
268 | cupsFileClose(fp); | |
269 | ||
270 | cupsdLogMessage(CUPSD_LOG_INFO, | |
271 | "Created SSL server certificate file \"%s\"...", | |
272 | ServerCertificate); | |
273 | } | |
274 | else | |
275 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
276 | "Unable to create SSL server certificate file \"%s\" - %s", | |
277 | ServerCertificate, strerror(errno)); | |
278 | ||
279 | /* | |
280 | * Cleanup... | |
281 | */ | |
282 | ||
283 | gnutls_x509_crt_deinit(crt); | |
284 | gnutls_x509_privkey_deinit(key); | |
285 | ||
286 | return (1); | |
287 | } | |
288 | ||
289 | ||
290 | /* | |
a51f28ec | 291 | * End of "$Id: tls-gnutls.c 11899 2014-05-27 15:10:09Z msweet $". |
82cc1f9a | 292 | */ |