1/* 2 * "$Id: tls-gnutls.c 3757 2012-03-30 06:13:47Z msweet $" 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 27static int make_certificate(cupsd_client_t *con); 28 29 30/* 31 * 'cupsdEndTLS()' - Shutdown a secure session with the client. 32 */ 33 34int /* O - 1 on success, 0 on error */ 35cupsdEndTLS(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 72int /* O - 1 on success, 0 on error */ 73cupsdStartTLS(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); 120 gnutls_transport_set_ptr(con->http.tls, (gnutls_transport_ptr)HTTP(con)); 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 152static int /* O - 1 on success, 0 on failure */ 153make_certificate(cupsd_client_t *con) /* I - Client connection */ 154{ 155 gnutls_x509_crt crt; /* Self-signed certificate */ 156 gnutls_x509_privkey key; /* Encryption key */ 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/* 291 * End of "$Id: tls-gnutls.c 3757 2012-03-30 06:13:47Z msweet $". 292 */ 293