4 * TLS support code for the CUPS scheduler using OpenSSL.
6 * Copyright 2007-2012 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
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.
27 static int make_certificate(cupsd_client_t
*con
);
31 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
34 int /* O - 1 on success, 0 on error */
35 cupsdEndTLS(cupsd_client_t
*con
) /* I - Client connection */
37 SSL_CTX
*context
; /* Context for encryption */
38 unsigned long error
; /* Error code */
39 int status
; /* Return status */
42 context
= SSL_get_SSL_CTX(con
->http
.tls
);
44 switch (SSL_shutdown(con
->http
.tls
))
47 cupsdLogMessage(CUPSD_LOG_DEBUG
,
48 "SSL shutdown successful!");
53 cupsdLogMessage(CUPSD_LOG_ERROR
,
54 "Fatal error during SSL shutdown!");
57 while ((error
= ERR_get_error()) != 0)
58 cupsdLogMessage(CUPSD_LOG_ERROR
, "SSL shutdown failed: %s",
59 ERR_error_string(error
, NULL
));
64 SSL_CTX_free(context
);
65 SSL_free(con
->http
.tls
);
73 * 'cupsdStartTLS()' - Start a secure session with the client.
76 int /* O - 1 on success, 0 on error */
77 cupsdStartTLS(cupsd_client_t
*con
) /* I - Client connection */
79 SSL_CTX
*context
; /* Context for encryption */
80 BIO
*bio
; /* BIO data */
81 unsigned long error
; /* Error code */
84 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Client %d] Encrypting connection.",
88 * Verify that we have a certificate...
91 if (access(ServerKey
, 0) || access(ServerCertificate
, 0))
94 * Nope, make a self-signed certificate...
97 if (!make_certificate(con
))
102 * Create the SSL context and accept the connection...
105 context
= SSL_CTX_new(SSLv23_server_method());
107 SSL_CTX_set_options(context
, SSL_OP_NO_SSLv2
); /* Only use SSLv3 or TLS */
108 if (SSLOptions
& CUPSD_SSL_NOEMPTY
)
109 SSL_CTX_set_options(context
, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
);
110 SSL_CTX_use_PrivateKey_file(context
, ServerKey
, SSL_FILETYPE_PEM
);
111 SSL_CTX_use_certificate_chain_file(context
, ServerCertificate
);
113 bio
= BIO_new(_httpBIOMethods());
114 BIO_ctrl(bio
, BIO_C_SET_FILE_PTR
, 0, (char *)HTTP(con
));
116 con
->http
.tls
= SSL_new(context
);
117 SSL_set_bio(con
->http
.tls
, bio
, bio
);
119 if (SSL_accept(con
->http
.tls
) != 1)
121 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to encrypt connection from %s.",
124 while ((error
= ERR_get_error()) != 0)
125 cupsdLogMessage(CUPSD_LOG_ERROR
, "%s", ERR_error_string(error
, NULL
));
127 SSL_CTX_free(context
);
128 SSL_free(con
->http
.tls
);
129 con
->http
.tls
= NULL
;
133 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Connection from %s now encrypted.",
141 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
144 static int /* O - 1 on success, 0 on failure */
145 make_certificate(cupsd_client_t
*con
) /* I - Client connection */
148 int pid
, /* Process ID of command */
149 status
; /* Status of command */
150 char command
[1024], /* Command */
151 *argv
[12], /* Command-line arguments */
152 *envp
[MAX_ENV
+ 1], /* Environment variables */
153 infofile
[1024], /* Type-in information for cert */
154 seedfile
[1024]; /* Random number seed file */
155 int envc
, /* Number of environment variables */
156 bytes
; /* Bytes written */
157 cups_file_t
*fp
; /* Seed/info file */
158 int infofd
; /* Info file descriptor */
162 * Run the "openssl" command to seed the random number generator and
163 * generate a self-signed certificate that is good for 10 years:
165 * openssl rand -rand seedfile 1
167 * openssl req -new -x509 -keyout ServerKey \
168 * -out ServerCertificate -days 3650 -nodes
170 * The seeding step is crucial in ensuring that the openssl command
171 * does not block on systems without sufficient entropy...
174 if (!cupsFileFind("openssl", getenv("PATH"), 1, command
, sizeof(command
)))
176 cupsdLogMessage(CUPSD_LOG_ERROR
,
177 "No SSL certificate and openssl command not found!");
181 if (access("/dev/urandom", 0))
184 * If the system doesn't provide /dev/urandom, then any random source
185 * will probably be blocking-style, so generate some random data to
186 * use as a seed for the certificate. Note that we have already
187 * seeded the random number generator in cupsdInitCerts()...
190 cupsdLogMessage(CUPSD_LOG_INFO
,
191 "Seeding the random number generator...");
194 * Write the seed file...
197 if ((fp
= cupsTempFile2(seedfile
, sizeof(seedfile
))) == NULL
)
199 cupsdLogMessage(CUPSD_LOG_ERROR
, "Unable to create seed file %s - %s",
200 seedfile
, strerror(errno
));
204 for (bytes
= 0; bytes
< 262144; bytes
++)
205 cupsFilePutChar(fp
, CUPS_RAND());
210 * Run the openssl command to seed its random number generator...
220 envc
= cupsdLoadEnv(envp
, MAX_ENV
);
223 if (!cupsdStartProcess(command
, argv
, envp
, -1, -1, -1, -1, -1, 1, NULL
,
230 while (waitpid(pid
, &status
, 0) < 0)
237 cupsdFinishProcess(pid
, command
, sizeof(command
), NULL
);
240 * Remove the seed file, as it is no longer needed...
247 if (WIFEXITED(status
))
248 cupsdLogMessage(CUPSD_LOG_ERROR
,
249 "Unable to seed random number generator - "
250 "the openssl command stopped with status %d!",
251 WEXITSTATUS(status
));
253 cupsdLogMessage(CUPSD_LOG_ERROR
,
254 "Unable to seed random number generator - "
255 "the openssl command crashed on signal %d!",
263 * Create a file with the certificate information fields...
265 * Note: This assumes that the default questions are asked by the openssl
269 if ((fp
= cupsTempFile2(infofile
, sizeof(infofile
))) == NULL
)
271 cupsdLogMessage(CUPSD_LOG_ERROR
,
272 "Unable to create certificate information file %s - %s",
273 infofile
, strerror(errno
));
277 cupsFilePrintf(fp
, ".\n.\n.\n%s\n.\n%s\n%s\n",
278 ServerName
, ServerName
, ServerAdmin
);
281 cupsdLogMessage(CUPSD_LOG_INFO
,
282 "Generating SSL server key and certificate...");
291 argv
[7] = ServerCertificate
;
297 cupsdLoadEnv(envp
, MAX_ENV
);
299 infofd
= open(infofile
, O_RDONLY
);
301 if (!cupsdStartProcess(command
, argv
, envp
, infofd
, -1, -1, -1, -1, 1, NULL
,
312 while (waitpid(pid
, &status
, 0) < 0)
319 cupsdFinishProcess(pid
, command
, sizeof(command
), NULL
);
323 if (WIFEXITED(status
))
324 cupsdLogMessage(CUPSD_LOG_ERROR
,
325 "Unable to create SSL server key and certificate - "
326 "the openssl command stopped with status %d!",
327 WEXITSTATUS(status
));
329 cupsdLogMessage(CUPSD_LOG_ERROR
,
330 "Unable to create SSL server key and certificate - "
331 "the openssl command crashed on signal %d!",
336 cupsdLogMessage(CUPSD_LOG_INFO
, "Created SSL server key file \"%s\"...",
338 cupsdLogMessage(CUPSD_LOG_INFO
,
339 "Created SSL server certificate file \"%s\"...",
347 #endif /* HAVE_WAITPID */