]>
Commit | Line | Data |
---|---|---|
2c85b752 MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * TLS support code for CUPS using GNU TLS. | |
5 | * | |
6 | * Copyright 2007-2013 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 | * This file is subject to the Apple OS-Developed Software exception. | |
16 | */ | |
17 | ||
18 | ||
07623986 MS |
19 | /* |
20 | * Local globals... | |
21 | */ | |
22 | ||
23 | static int tls_auto_create = 0; | |
24 | /* Auto-create self-signed certs? */ | |
25 | static char *tls_common_name = NULL; | |
26 | /* Default common name */ | |
27 | static char *tls_keypath = NULL; | |
28 | /* Server cert keychain path */ | |
29 | static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; | |
30 | /* Mutex for keychain/certs */ | |
31 | ||
32 | ||
2c85b752 MS |
33 | /* |
34 | * Local functions... | |
35 | */ | |
36 | ||
dd332638 MS |
37 | //static int make_certificate(cupsd_client_t *con); |
38 | static ssize_t http_gnutls_read(gnutls_transport_ptr_t ptr, void *data, size_t length); | |
39 | static ssize_t http_gnutls_write(gnutls_transport_ptr_t ptr, const void *data, size_t length); | |
40 | ||
41 | ||
07623986 MS |
42 | /* |
43 | * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair. | |
44 | * | |
45 | * @since CUPS 2.0@ | |
46 | */ | |
47 | ||
48 | int /* O - 1 on success, 0 on failure */ | |
49 | cupsMakeServerCredentials( | |
50 | const char *path, /* I - Path to keychain/directory */ | |
51 | const char *common_name, /* I - Common name */ | |
52 | int num_alt_names, /* I - Number of subject alternate names */ | |
53 | const char **alt_names, /* I - Subject Alternate Names */ | |
54 | time_t expiration_date) /* I - Expiration date */ | |
55 | { | |
56 | (void)path; | |
57 | (void)common_name; | |
58 | (void)num_alt_names; | |
59 | (void)alt_names; | |
60 | (void)expiration_date; | |
61 | ||
62 | return (0); | |
63 | } | |
64 | ||
65 | ||
66 | /* | |
67 | * 'cupsSetServerCredentials()' - Set the default server credentials. | |
68 | * | |
69 | * Note: The server credentials are used by all threads in the running process. | |
70 | * This function is threadsafe. | |
71 | * | |
72 | * @since CUPS 2.0@ | |
73 | */ | |
74 | ||
75 | int /* O - 1 on success, 0 on failure */ | |
76 | cupsSetServerCredentials( | |
77 | const char *path, /* I - Path to keychain/directory */ | |
78 | const char *common_name, /* I - Default common name for server */ | |
79 | int auto_create) /* I - 1 = automatically create self-signed certificates */ | |
80 | { | |
81 | _cupsMutexLock(&tls_mutex); | |
82 | ||
83 | /* | |
84 | * Free old values... | |
85 | */ | |
86 | ||
87 | if (tls_keypath) | |
88 | _cupsStrFree(tls_keypath); | |
89 | ||
90 | if (tls_common_name) | |
91 | _cupsStrFree(tls_common_name); | |
92 | ||
93 | /* | |
94 | * Save the new values... | |
95 | */ | |
96 | ||
97 | tls_keypath = _cupsStrAlloc(path); | |
98 | tls_auto_create = auto_create; | |
99 | tls_common_name = _cupsStrAlloc(common_name); | |
100 | ||
101 | _cupsMutexUnlock(&tls_mutex); | |
102 | ||
103 | return (1); | |
104 | } | |
105 | ||
106 | ||
dd332638 MS |
107 | /* |
108 | * 'httpCopyCredentials()' - Copy the credentials associated with the peer in | |
109 | * an encrypted connection. | |
110 | * | |
111 | * @since CUPS 1.5/OS X 10.7@ | |
112 | */ | |
113 | ||
114 | int /* O - Status of call (0 = success) */ | |
115 | httpCopyCredentials( | |
116 | http_t *http, /* I - Connection to server */ | |
117 | cups_array_t **credentials) /* O - Array of credentials */ | |
118 | { | |
119 | if (credentials) | |
120 | *credentials = NULL; | |
121 | ||
122 | if (!http || !http->tls || !credentials) | |
123 | return (-1); | |
124 | ||
125 | return (0); | |
126 | } | |
127 | ||
128 | ||
129 | /* | |
130 | * '_httpCreateCredentials()' - Create credentials in the internal format. | |
131 | */ | |
132 | ||
133 | http_tls_credentials_t /* O - Internal credentials */ | |
134 | _httpCreateCredentials( | |
135 | cups_array_t *credentials) /* I - Array of credentials */ | |
136 | { | |
137 | (void)credentials; | |
138 | ||
139 | return (NULL); | |
140 | } | |
141 | ||
142 | ||
143 | /* | |
144 | * '_httpFreeCredentials()' - Free internal credentials. | |
145 | */ | |
146 | ||
147 | void | |
148 | _httpFreeCredentials( | |
149 | http_tls_credentials_t credentials) /* I - Internal credentials */ | |
150 | { | |
151 | (void)credentials; | |
152 | } | |
153 | ||
154 | ||
155 | /* | |
156 | * 'http_gnutls_read()' - Read function for the GNU TLS library. | |
157 | */ | |
158 | ||
159 | static ssize_t /* O - Number of bytes read or -1 on error */ | |
160 | http_gnutls_read( | |
161 | gnutls_transport_ptr_t ptr, /* I - Connection to server */ | |
162 | void *data, /* I - Buffer */ | |
163 | size_t length) /* I - Number of bytes to read */ | |
164 | { | |
165 | http_t *http; /* HTTP connection */ | |
166 | ssize_t bytes; /* Bytes read */ | |
167 | ||
168 | ||
169 | DEBUG_printf(("6http_gnutls_read(ptr=%p, data=%p, length=%d)", ptr, data, (int)length)); | |
170 | ||
171 | http = (http_t *)ptr; | |
172 | ||
173 | if (!http->blocking) | |
174 | { | |
175 | /* | |
176 | * Make sure we have data before we read... | |
177 | */ | |
178 | ||
179 | while (!_httpWait(http, http->wait_value, 0)) | |
180 | { | |
181 | if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) | |
182 | continue; | |
183 | ||
184 | http->error = ETIMEDOUT; | |
185 | return (-1); | |
186 | } | |
187 | } | |
188 | ||
189 | bytes = recv(http->fd, data, length, 0); | |
190 | DEBUG_printf(("6http_gnutls_read: bytes=%d", (int)bytes)); | |
191 | return (bytes); | |
192 | } | |
193 | ||
194 | ||
195 | /* | |
196 | * 'http_gnutls_write()' - Write function for the GNU TLS library. | |
197 | */ | |
198 | ||
199 | static ssize_t /* O - Number of bytes written or -1 on error */ | |
200 | http_gnutls_write( | |
201 | gnutls_transport_ptr_t ptr, /* I - Connection to server */ | |
202 | const void *data, /* I - Data buffer */ | |
203 | size_t length) /* I - Number of bytes to write */ | |
204 | { | |
205 | ssize_t bytes; /* Bytes written */ | |
206 | ||
207 | ||
208 | DEBUG_printf(("6http_gnutls_write(ptr=%p, data=%p, length=%d)", ptr, data, | |
209 | (int)length)); | |
210 | #ifdef DEBUG | |
211 | http_debug_hex("http_gnutls_write", data, (int)length); | |
212 | #endif /* DEBUG */ | |
213 | ||
214 | bytes = send(((http_t *)ptr)->fd, data, length, 0); | |
215 | DEBUG_printf(("http_gnutls_write: bytes=%d", (int)bytes)); | |
216 | ||
217 | return (bytes); | |
218 | } | |
2c85b752 MS |
219 | |
220 | ||
221 | /* | |
222 | * 'http_tls_initialize()' - Initialize the TLS stack. | |
223 | */ | |
224 | ||
225 | static void | |
226 | http_tls_initialize(void) | |
227 | { | |
2c85b752 MS |
228 | /* |
229 | * Initialize GNU TLS... | |
230 | */ | |
231 | ||
232 | gnutls_global_init(); | |
dd332638 | 233 | } |
2c85b752 | 234 | |
2c85b752 | 235 | |
dd332638 MS |
236 | /* |
237 | * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes. | |
238 | */ | |
2c85b752 | 239 | |
dd332638 MS |
240 | static size_t |
241 | http_tls_pending(http_t *http) /* I - HTTP connection */ | |
242 | { | |
243 | return (gnutls_record_check_pending(http->tls)); | |
2c85b752 MS |
244 | } |
245 | ||
246 | ||
2c85b752 MS |
247 | /* |
248 | * 'http_tls_read()' - Read from a SSL/TLS connection. | |
249 | */ | |
250 | ||
251 | static int /* O - Bytes read */ | |
252 | http_tls_read(http_t *http, /* I - Connection to server */ | |
253 | char *buf, /* I - Buffer to store data */ | |
254 | int len) /* I - Length of buffer */ | |
255 | { | |
2c85b752 MS |
256 | ssize_t result; /* Return value */ |
257 | ||
258 | ||
07623986 | 259 | result = gnutls_record_recv(http->tls, buf, (size_t)len); |
2c85b752 MS |
260 | |
261 | if (result < 0 && !errno) | |
262 | { | |
263 | /* | |
264 | * Convert GNU TLS error to errno value... | |
265 | */ | |
266 | ||
267 | switch (result) | |
268 | { | |
269 | case GNUTLS_E_INTERRUPTED : | |
270 | errno = EINTR; | |
271 | break; | |
272 | ||
273 | case GNUTLS_E_AGAIN : | |
274 | errno = EAGAIN; | |
275 | break; | |
276 | ||
277 | default : | |
278 | errno = EPIPE; | |
279 | break; | |
280 | } | |
281 | ||
282 | result = -1; | |
283 | } | |
284 | ||
285 | return ((int)result); | |
dd332638 | 286 | } |
2c85b752 MS |
287 | |
288 | ||
dd332638 MS |
289 | /* |
290 | * 'http_tls_set_credentials()' - Set the TLS credentials. | |
291 | */ | |
2c85b752 | 292 | |
dd332638 MS |
293 | static int /* O - Status of connection */ |
294 | http_tls_set_credentials(http_t *http) /* I - Connection to server */ | |
295 | { | |
296 | (void)http; | |
2c85b752 | 297 | |
dd332638 | 298 | return (0); |
2c85b752 | 299 | } |
2c85b752 MS |
300 | |
301 | ||
2c85b752 | 302 | /* |
dd332638 | 303 | * 'http_tls_start()' - Set up SSL/TLS support on a connection. |
2c85b752 MS |
304 | */ |
305 | ||
306 | static int /* O - 0 on success, -1 on failure */ | |
dd332638 | 307 | http_tls_start(http_t *http) /* I - Connection to server */ |
2c85b752 MS |
308 | { |
309 | char hostname[256], /* Hostname */ | |
310 | *hostptr; /* Pointer into hostname */ | |
2c85b752 MS |
311 | int status; /* Status of handshake */ |
312 | gnutls_certificate_client_credentials *credentials; | |
313 | /* TLS credentials */ | |
2c85b752 MS |
314 | |
315 | ||
316 | DEBUG_printf(("7http_setup_ssl(http=%p)", http)); | |
317 | ||
318 | /* | |
319 | * Get the hostname to use for SSL... | |
320 | */ | |
321 | ||
322 | if (httpAddrLocalhost(http->hostaddr)) | |
323 | { | |
324 | strlcpy(hostname, "localhost", sizeof(hostname)); | |
325 | } | |
326 | else | |
327 | { | |
328 | /* | |
329 | * Otherwise make sure the hostname we have does not end in a trailing dot. | |
330 | */ | |
331 | ||
332 | strlcpy(hostname, http->hostname, sizeof(hostname)); | |
333 | if ((hostptr = hostname + strlen(hostname) - 1) >= hostname && | |
334 | *hostptr == '.') | |
335 | *hostptr = '\0'; | |
336 | } | |
337 | ||
2c85b752 MS |
338 | credentials = (gnutls_certificate_client_credentials *) |
339 | malloc(sizeof(gnutls_certificate_client_credentials)); | |
340 | if (credentials == NULL) | |
341 | { | |
342 | DEBUG_printf(("8http_setup_ssl: Unable to allocate credentials: %s", | |
343 | strerror(errno))); | |
344 | http->error = errno; | |
345 | http->status = HTTP_STATUS_ERROR; | |
346 | _cupsSetHTTPError(HTTP_STATUS_ERROR); | |
347 | ||
348 | return (-1); | |
349 | } | |
350 | ||
351 | gnutls_certificate_allocate_credentials(credentials); | |
352 | ||
353 | gnutls_init(&http->tls, GNUTLS_CLIENT); | |
354 | gnutls_set_default_priority(http->tls); | |
355 | gnutls_server_name_set(http->tls, GNUTLS_NAME_DNS, hostname, | |
356 | strlen(hostname)); | |
357 | gnutls_credentials_set(http->tls, GNUTLS_CRD_CERTIFICATE, *credentials); | |
dd332638 MS |
358 | gnutls_transport_set_ptr(http->tls, (gnutls_transport_ptr_t)http); |
359 | gnutls_transport_set_pull_function(http->tls, http_gnutls_read); | |
360 | gnutls_transport_set_push_function(http->tls, http_gnutls_write); | |
2c85b752 MS |
361 | |
362 | while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS) | |
363 | { | |
364 | DEBUG_printf(("8http_setup_ssl: gnutls_handshake returned %d (%s)", | |
365 | status, gnutls_strerror(status))); | |
366 | ||
367 | if (gnutls_error_is_fatal(status)) | |
368 | { | |
369 | http->error = EIO; | |
370 | http->status = HTTP_STATUS_ERROR; | |
371 | ||
372 | _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI, gnutls_strerror(status), 0); | |
373 | ||
374 | gnutls_deinit(http->tls); | |
375 | gnutls_certificate_free_credentials(*credentials); | |
376 | free(credentials); | |
377 | http->tls = NULL; | |
378 | ||
379 | return (-1); | |
380 | } | |
381 | } | |
382 | ||
383 | http->tls_credentials = credentials; | |
384 | ||
dd332638 MS |
385 | // TODO: Put this in the right place; no-op for now, this to get things to compile |
386 | http_tls_set_credentials(http); | |
2c85b752 MS |
387 | |
388 | return (0); | |
389 | } | |
390 | ||
391 | ||
392 | /* | |
dd332638 | 393 | * 'http_tls_stop()' - Shut down SSL/TLS on a connection. |
2c85b752 MS |
394 | */ |
395 | ||
396 | static void | |
dd332638 | 397 | http_tls_stop(http_t *http) /* I - Connection to server */ |
2c85b752 | 398 | { |
2c85b752 MS |
399 | gnutls_certificate_client_credentials *credentials; |
400 | /* TLS credentials */ | |
401 | ||
402 | credentials = (gnutls_certificate_client_credentials *)(http->tls_credentials); | |
403 | ||
404 | gnutls_bye(http->tls, GNUTLS_SHUT_RDWR); | |
405 | gnutls_deinit(http->tls); | |
406 | gnutls_certificate_free_credentials(*credentials); | |
407 | free(credentials); | |
2c85b752 | 408 | } |
2c85b752 MS |
409 | |
410 | ||
2c85b752 | 411 | /* |
dd332638 | 412 | * 'http_tls_write()' - Write to a SSL/TLS connection. |
2c85b752 MS |
413 | */ |
414 | ||
415 | static int /* O - Bytes written */ | |
dd332638 | 416 | http_tls_write(http_t *http, /* I - Connection to server */ |
2c85b752 MS |
417 | const char *buf, /* I - Buffer holding data */ |
418 | int len) /* I - Length of buffer */ | |
419 | { | |
420 | ssize_t result; /* Return value */ | |
421 | ||
422 | ||
423 | DEBUG_printf(("2http_write_ssl(http=%p, buf=%p, len=%d)", http, buf, len)); | |
424 | ||
07623986 | 425 | result = gnutls_record_send(http->tls, buf, (size_t)len); |
2c85b752 MS |
426 | |
427 | if (result < 0 && !errno) | |
428 | { | |
429 | /* | |
430 | * Convert GNU TLS error to errno value... | |
431 | */ | |
432 | ||
433 | switch (result) | |
434 | { | |
435 | case GNUTLS_E_INTERRUPTED : | |
436 | errno = EINTR; | |
437 | break; | |
438 | ||
439 | case GNUTLS_E_AGAIN : | |
440 | errno = EAGAIN; | |
441 | break; | |
442 | ||
443 | default : | |
444 | errno = EPIPE; | |
445 | break; | |
446 | } | |
447 | ||
448 | result = -1; | |
449 | } | |
450 | ||
2c85b752 MS |
451 | DEBUG_printf(("3http_write_ssl: Returning %d.", (int)result)); |
452 | ||
453 | return ((int)result); | |
454 | } | |
2c85b752 MS |
455 | |
456 | ||
dd332638 | 457 | #if 0 |
2c85b752 MS |
458 | /* |
459 | * 'cupsdEndTLS()' - Shutdown a secure session with the client. | |
460 | */ | |
461 | ||
462 | int /* O - 1 on success, 0 on error */ | |
463 | cupsdEndTLS(cupsd_client_t *con) /* I - Client connection */ | |
464 | { | |
465 | int error; /* Error code */ | |
466 | gnutls_certificate_server_credentials *credentials; | |
467 | /* TLS credentials */ | |
468 | ||
469 | ||
470 | credentials = (gnutls_certificate_server_credentials *) | |
471 | (con->http.tls_credentials); | |
472 | ||
473 | error = gnutls_bye(con->http.tls, GNUTLS_SHUT_WR); | |
474 | switch (error) | |
475 | { | |
476 | case GNUTLS_E_SUCCESS: | |
477 | cupsdLogMessage(CUPSD_LOG_DEBUG, | |
478 | "SSL shutdown successful!"); | |
479 | break; | |
480 | default: | |
481 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
482 | "SSL shutdown failed: %s", gnutls_strerror(error)); | |
483 | break; | |
484 | } | |
485 | ||
486 | gnutls_deinit(con->http.tls); | |
487 | con->http.tls = NULL; | |
488 | ||
489 | gnutls_certificate_free_credentials(*credentials); | |
490 | free(credentials); | |
491 | ||
492 | return (1); | |
493 | } | |
494 | ||
495 | ||
496 | /* | |
497 | * 'cupsdStartTLS()' - Start a secure session with the client. | |
498 | */ | |
499 | ||
500 | int /* O - 1 on success, 0 on error */ | |
501 | cupsdStartTLS(cupsd_client_t *con) /* I - Client connection */ | |
502 | { | |
503 | int status; /* Error code */ | |
504 | gnutls_certificate_server_credentials *credentials; | |
505 | /* TLS credentials */ | |
506 | ||
507 | ||
508 | cupsdLogMessage(CUPSD_LOG_DEBUG, "[Client %d] Encrypting connection.", | |
509 | con->http.fd); | |
510 | ||
511 | /* | |
512 | * Verify that we have a certificate... | |
513 | */ | |
514 | ||
515 | if (access(ServerKey, 0) || access(ServerCertificate, 0)) | |
516 | { | |
517 | /* | |
518 | * Nope, make a self-signed certificate... | |
519 | */ | |
520 | ||
521 | if (!make_certificate(con)) | |
522 | return (0); | |
523 | } | |
524 | ||
525 | /* | |
526 | * Create the SSL object and perform the SSL handshake... | |
527 | */ | |
528 | ||
529 | credentials = (gnutls_certificate_server_credentials *) | |
530 | malloc(sizeof(gnutls_certificate_server_credentials)); | |
531 | if (credentials == NULL) | |
532 | { | |
533 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
534 | "Unable to encrypt connection from %s - %s", | |
535 | con->http.hostname, strerror(errno)); | |
536 | ||
537 | return (0); | |
538 | } | |
539 | ||
540 | gnutls_certificate_allocate_credentials(credentials); | |
541 | gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, | |
542 | ServerKey, GNUTLS_X509_FMT_PEM); | |
543 | ||
544 | gnutls_init(&con->http.tls, GNUTLS_SERVER); | |
545 | gnutls_set_default_priority(con->http.tls); | |
546 | ||
547 | gnutls_credentials_set(con->http.tls, GNUTLS_CRD_CERTIFICATE, *credentials); | |
dd332638 MS |
548 | gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr_t)HTTP(con)); |
549 | gnutls_transport_set_pull_function(con->http.tls, http_gnutls_read); | |
550 | gnutls_transport_set_push_function(con->http.tls, http_gnutls_write); | |
2c85b752 MS |
551 | |
552 | while ((status = gnutls_handshake(con->http.tls)) != GNUTLS_E_SUCCESS) | |
553 | { | |
554 | if (gnutls_error_is_fatal(status)) | |
555 | { | |
556 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
557 | "Unable to encrypt connection from %s - %s", | |
558 | con->http.hostname, gnutls_strerror(status)); | |
559 | ||
560 | gnutls_deinit(con->http.tls); | |
561 | gnutls_certificate_free_credentials(*credentials); | |
562 | con->http.tls = NULL; | |
563 | free(credentials); | |
564 | return (0); | |
565 | } | |
566 | } | |
567 | ||
568 | cupsdLogMessage(CUPSD_LOG_DEBUG, "Connection from %s now encrypted.", | |
569 | con->http.hostname); | |
570 | ||
571 | con->http.tls_credentials = credentials; | |
572 | return (1); | |
573 | } | |
574 | ||
575 | ||
576 | /* | |
577 | * 'make_certificate()' - Make a self-signed SSL/TLS certificate. | |
578 | */ | |
579 | ||
580 | static int /* O - 1 on success, 0 on failure */ | |
581 | make_certificate(cupsd_client_t *con) /* I - Client connection */ | |
582 | { | |
583 | gnutls_x509_crt crt; /* Self-signed certificate */ | |
584 | gnutls_x509_privkey key; /* Encryption key */ | |
585 | cups_lang_t *language; /* Default language info */ | |
586 | cups_file_t *fp; /* Key/cert file */ | |
587 | unsigned char buffer[8192]; /* Buffer for x509 data */ | |
588 | size_t bytes; /* Number of bytes of data */ | |
589 | unsigned char serial[4]; /* Serial number buffer */ | |
590 | time_t curtime; /* Current time */ | |
591 | int result; /* Result of GNU TLS calls */ | |
592 | ||
593 | ||
594 | /* | |
595 | * Create the encryption key... | |
596 | */ | |
597 | ||
598 | cupsdLogMessage(CUPSD_LOG_INFO, "Generating SSL server key..."); | |
599 | ||
600 | gnutls_x509_privkey_init(&key); | |
601 | gnutls_x509_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); | |
602 | ||
603 | /* | |
604 | * Save it... | |
605 | */ | |
606 | ||
607 | bytes = sizeof(buffer); | |
608 | ||
609 | if ((result = gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, | |
610 | buffer, &bytes)) < 0) | |
611 | { | |
612 | cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to export SSL server key - %s", | |
613 | gnutls_strerror(result)); | |
614 | gnutls_x509_privkey_deinit(key); | |
615 | return (0); | |
616 | } | |
617 | else if ((fp = cupsFileOpen(ServerKey, "w")) != NULL) | |
618 | { | |
619 | cupsFileWrite(fp, (char *)buffer, bytes); | |
620 | cupsFileClose(fp); | |
621 | ||
622 | cupsdLogMessage(CUPSD_LOG_INFO, "Created SSL server key file \"%s\"...", | |
623 | ServerKey); | |
624 | } | |
625 | else | |
626 | { | |
627 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
628 | "Unable to create SSL server key file \"%s\" - %s", | |
629 | ServerKey, strerror(errno)); | |
630 | gnutls_x509_privkey_deinit(key); | |
631 | return (0); | |
632 | } | |
633 | ||
634 | /* | |
635 | * Create the self-signed certificate... | |
636 | */ | |
637 | ||
638 | cupsdLogMessage(CUPSD_LOG_INFO, "Generating self-signed SSL certificate..."); | |
639 | ||
640 | language = cupsLangDefault(); | |
641 | curtime = time(NULL); | |
642 | serial[0] = curtime >> 24; | |
643 | serial[1] = curtime >> 16; | |
644 | serial[2] = curtime >> 8; | |
645 | serial[3] = curtime; | |
646 | ||
647 | gnutls_x509_crt_init(&crt); | |
648 | if (strlen(language->language) == 5) | |
649 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, | |
650 | language->language + 3, 2); | |
651 | else | |
652 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COUNTRY_NAME, 0, | |
653 | "US", 2); | |
654 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_COMMON_NAME, 0, | |
655 | ServerName, strlen(ServerName)); | |
656 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATION_NAME, 0, | |
657 | ServerName, strlen(ServerName)); | |
658 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_ORGANIZATIONAL_UNIT_NAME, | |
659 | 0, "Unknown", 7); | |
660 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_STATE_OR_PROVINCE_NAME, 0, | |
661 | "Unknown", 7); | |
662 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_X520_LOCALITY_NAME, 0, | |
663 | "Unknown", 7); | |
664 | gnutls_x509_crt_set_dn_by_oid(crt, GNUTLS_OID_PKCS9_EMAIL, 0, | |
665 | ServerAdmin, strlen(ServerAdmin)); | |
666 | gnutls_x509_crt_set_key(crt, key); | |
667 | gnutls_x509_crt_set_serial(crt, serial, sizeof(serial)); | |
668 | gnutls_x509_crt_set_activation_time(crt, curtime); | |
669 | gnutls_x509_crt_set_expiration_time(crt, curtime + 10 * 365 * 86400); | |
670 | gnutls_x509_crt_set_ca_status(crt, 0); | |
671 | gnutls_x509_crt_set_subject_alternative_name(crt, GNUTLS_SAN_DNSNAME, | |
672 | ServerName); | |
673 | gnutls_x509_crt_set_key_purpose_oid(crt, GNUTLS_KP_TLS_WWW_SERVER, 0); | |
674 | gnutls_x509_crt_set_key_usage(crt, GNUTLS_KEY_KEY_ENCIPHERMENT); | |
675 | gnutls_x509_crt_set_version(crt, 3); | |
676 | ||
677 | bytes = sizeof(buffer); | |
678 | if (gnutls_x509_crt_get_key_id(crt, 0, buffer, &bytes) >= 0) | |
679 | gnutls_x509_crt_set_subject_key_id(crt, buffer, bytes); | |
680 | ||
681 | gnutls_x509_crt_sign(crt, crt, key); | |
682 | ||
683 | /* | |
684 | * Save it... | |
685 | */ | |
686 | ||
687 | bytes = sizeof(buffer); | |
688 | if ((result = gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, | |
689 | buffer, &bytes)) < 0) | |
690 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
691 | "Unable to export SSL server certificate - %s", | |
692 | gnutls_strerror(result)); | |
693 | else if ((fp = cupsFileOpen(ServerCertificate, "w")) != NULL) | |
694 | { | |
695 | cupsFileWrite(fp, (char *)buffer, bytes); | |
696 | cupsFileClose(fp); | |
697 | ||
698 | cupsdLogMessage(CUPSD_LOG_INFO, | |
699 | "Created SSL server certificate file \"%s\"...", | |
700 | ServerCertificate); | |
701 | } | |
702 | else | |
703 | cupsdLogMessage(CUPSD_LOG_ERROR, | |
704 | "Unable to create SSL server certificate file \"%s\" - %s", | |
705 | ServerCertificate, strerror(errno)); | |
706 | ||
707 | /* | |
708 | * Cleanup... | |
709 | */ | |
710 | ||
711 | gnutls_x509_crt_deinit(crt); | |
712 | gnutls_x509_privkey_deinit(key); | |
713 | ||
714 | return (1); | |
715 | } | |
dd332638 | 716 | #endif /* 0 */ |
2c85b752 MS |
717 | |
718 | ||
719 | /* | |
720 | * End of "$Id$". | |
721 | */ |