4 * TLS support code for CUPS on OS X.
6 * Copyright 2007-2013 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/".
15 * This file is subject to the Apple OS-Developed Software exception.
18 /**** This file is included from http.c ****/
21 * Include necessary headers...
26 extern char **environ
;
33 static _cups_mutex_t tls_mutex
= _CUPS_MUTEX_INITIALIZER
;
34 /* Mutex for keychain/certs */
35 static SecKeychainRef tls_keychain
= NULL
;
36 /* Server cert keychain */
37 static int tls_auto_create
= 0;
38 /* Auto-create self-signed certs? */
39 static char *tls_common_name
= NULL
;
40 /* Default common name */
47 static OSStatus
http_cdsa_read(SSLConnectionRef connection
, void *data
,
49 static OSStatus
http_cdsa_write(SSLConnectionRef connection
, const void *data
,
54 * 'cupsMakeServerCredentials()' - Make a self-signed certificate and private key pair.
59 int /* O - 1 on success, 0 on failure */
60 cupsMakeServerCredentials(
61 const char *path
, /* I - Path to keychain/directory */
62 const char *common_name
, /* I - Common name */
63 int num_alt_names
, /* I - Number of subject alternate names */
64 const char **alt_names
, /* I - Subject Alternate Names */
65 time_t expiration_date
) /* I - Expiration date */
71 (void)expiration_date
;
78 * 'cupsSetServerCredentials()' - Set the default server credentials.
80 * Note: The server credentials are used by all threads in the running process.
81 * This function is threadsafe.
86 int /* O - 1 on success, 0 on failure */
87 cupsSetServerCredentials(
88 const char *path
, /* I - Path to keychain/directory */
89 const char *common_name
, /* I - Default common name for server */
90 int auto_create
) /* I - 1 = automatically create self-signed certificates */
92 SecKeychainRef keychain
= NULL
;/* Temporary keychain */
95 if (SecKeychainOpen(path
, &keychain
) != noErr
)
97 /* TODO: Set cups last error string */
101 _cupsMutexLock(&tls_mutex
);
104 * Close any keychain that is currently open...
108 CFRelease(tls_keychain
);
111 _cupsStrFree(tls_common_name
);
114 * Save the new keychain...
117 tls_keychain
= keychain
;
118 tls_auto_create
= auto_create
;
119 tls_common_name
= _cupsStrAlloc(common_name
);
121 _cupsMutexUnlock(&tls_mutex
);
128 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
129 * an encrypted connection.
131 * @since CUPS 1.5/OS X 10.7@
134 int /* O - Status of call (0 = success) */
136 http_t
*http
, /* I - Connection to server */
137 cups_array_t
**credentials
) /* O - Array of credentials */
139 OSStatus error
; /* Error code */
140 SecTrustRef peerTrust
; /* Peer trust reference */
141 CFIndex count
; /* Number of credentials */
142 SecCertificateRef secCert
; /* Certificate reference */
143 CFDataRef data
; /* Certificate data */
144 int i
; /* Looping var */
150 if (!http
|| !http
->tls
|| !credentials
)
153 if (!(error
= SSLCopyPeerTrust(http
->tls
, &peerTrust
)) && peerTrust
)
155 if ((*credentials
= cupsArrayNew(NULL
, NULL
)) != NULL
)
157 count
= SecTrustGetCertificateCount(peerTrust
);
159 for (i
= 0; i
< count
; i
++)
161 secCert
= SecTrustGetCertificateAtIndex(peerTrust
, i
);
162 if ((data
= SecCertificateCopyData(secCert
)))
164 httpAddCredential(*credentials
, CFDataGetBytePtr(data
),
165 CFDataGetLength(data
));
171 CFRelease(peerTrust
);
179 * '_httpCreateCredentials()' - Create credentials in the internal format.
182 http_tls_credentials_t
/* O - Internal credentials */
183 _httpCreateCredentials(
184 cups_array_t
*credentials
) /* I - Array of credentials */
186 CFMutableArrayRef peerCerts
; /* Peer credentials reference */
187 SecCertificateRef secCert
; /* Certificate reference */
188 CFDataRef data
; /* Credential data reference */
189 http_credential_t
*credential
; /* Credential data */
195 if ((peerCerts
= CFArrayCreateMutable(kCFAllocatorDefault
,
196 cupsArrayCount(credentials
),
197 &kCFTypeArrayCallBacks
)) == NULL
)
200 for (credential
= (http_credential_t
*)cupsArrayFirst(credentials
);
202 credential
= (http_credential_t
*)cupsArrayNext(credentials
))
204 if ((data
= CFDataCreate(kCFAllocatorDefault
, credential
->data
,
205 credential
->datalen
)))
207 if ((secCert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
))
210 CFArrayAppendValue(peerCerts
, secCert
);
223 * 'httpCredentialsAreTrusted()' - Return whether the credentials are trusted.
228 int /* O - 1 if trusted, 0 if not/unknown */
229 httpCredentialsAreTrusted(
230 cups_array_t
*credentials
) /* I - Credentials */
239 * 'httpCredentialsGetExpiration()' - Return the expiration date of the credentials.
244 time_t /* O - Expiration date of credentials */
245 httpCredentialsGetExpiration(
246 cups_array_t
*credentials
) /* I - Credentials */
255 * 'httpCredentialsIsValidName()' - Return whether the credentials are valid for the given name.
260 int /* O - 1 if valid, 0 otherwise */
261 httpCredentialsIsValidName(
262 cups_array_t
*credentials
, /* I - Credentials */
263 const char *common_name
) /* I - Name to check */
273 * 'httpCredentialsString()' - Return a string representing the credentials.
278 size_t /* O - Total size of credentials string */
279 httpCredentialsString(
280 cups_array_t
*credentials
, /* I - Credentials */
281 char *buffer
, /* I - Buffer or @code NULL@ */
282 size_t bufsize
) /* I - Size of buffer */
286 if (buffer
&& bufsize
> 0)
294 * '_httpFreeCredentials()' - Free internal credentials.
298 _httpFreeCredentials(
299 http_tls_credentials_t credentials
) /* I - Internal credentials */
304 CFRelease(credentials
);
309 * 'httpLoadCredentials()' - Load X.509 credentials from a keychain file.
314 int /* O - 0 on success, -1 on error */
316 const char *path
, /* I - Keychain/PKCS#12 path */
317 cups_array_t
**credentials
, /* IO - Credentials */
318 const char *common_name
) /* I - Common name for credentials */
327 OSStatus err
; /* Error info */
328 SecKeychainRef keychain
= NULL
;/* Keychain reference */
329 SecIdentitySearchRef search
= NULL
; /* Search reference */
330 SecIdentityRef identity
= NULL
;/* Identity */
331 CFArrayRef certificates
= NULL
;
332 /* Certificate array */
333 SecPolicyRef policy
= NULL
; /* Policy ref */
334 CFStringRef cfcommon_name
= NULL
;
336 CFMutableDictionaryRef query
= NULL
; /* Query qualifiers */
337 CFArrayRef list
= NULL
; /* Keychain list */
340 if ((err
= SecKeychainOpen(path
, &keychain
)))
343 cfcommon_name
= CFStringCreateWithCString(kCFAllocatorDefault
, common_name
, kCFStringEncodingUTF8
);
345 policy
= SecPolicyCreateSSL(1, cfcommon_name
);
348 CFRelease(cfcommon_name
);
353 if (!(query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)))
356 list
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&keychain
, 1,
357 &kCFTypeArrayCallBacks
);
359 CFDictionaryAddValue(query
, kSecClass
, kSecClassIdentity
);
360 CFDictionaryAddValue(query
, kSecMatchPolicy
, policy
);
361 CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
);
362 CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitOne
);
363 CFDictionaryAddValue(query
, kSecMatchSearchList
, list
);
367 err
= SecItemCopyMatching(query
, (CFTypeRef
*)&identity
);
372 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
375 if ((certificates
= CFArrayCreate(NULL
, (const void **)&identity
, 1, &kCFTypeArrayCallBacks
)) == NULL
)
392 return (certificates
);
399 * 'cupsMakeCredentials()' - Create self-signed credentials for the given
405 int /* O - 0 on success, -1 on error */
407 const char *path
, /* I - Keychain/PKCS#12 path */
408 cups_array_t
**credentials
, /* O - Credentials */
409 const char *common_name
) /* I - Common name for X.509 cert */
411 # ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE
412 int status
= -1; /* Return status */
413 OSStatus err
; /* Error code (if any) */
414 CFStringRef cfcommon_name
= NULL
;
415 /* CF string for server name */
416 SecIdentityRef ident
= NULL
; /* Identity */
417 SecKeyRef publicKey
= NULL
,
421 CFMutableDictionaryRef keyParams
= NULL
;
422 /* Key generation parameters */
428 cfcommon_name
= CFStringCreateWithCString(kCFAllocatorDefault
, servername
,
429 kCFStringEncodingUTF8
);
434 * Create a public/private key pair...
437 keyParams
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
438 &kCFTypeDictionaryKeyCallBacks
,
439 &kCFTypeDictionaryValueCallBacks
);
443 CFDictionaryAddValue(keyParams
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
444 CFDictionaryAddValue(keyParams
, kSecAttrKeySizeInBits
, CFSTR("2048"));
445 CFDictionaryAddValue(keyParams
, kSecAttrLabel
,
446 CFSTR("CUPS Self-Signed Certificate"));
448 err
= SecKeyGeneratePair(keyParams
, &publicKey
, &privateKey
);
453 * Create a self-signed certificate using the public/private key pair...
456 CFIndex usageInt
= kSecKeyUsageAll
;
457 CFNumberRef usage
= CFNumberCreate(alloc
, kCFNumberCFIndexType
, &usageInt
);
458 CFDictionaryRef certParams
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
459 kSecCSRBasicContraintsPathLen
, CFINT(0), kSecSubjectAltName
, cfcommon_name
, kSecCertificateKeyUsage
, usage
, NULL
, NULL
);
462 const void *ca_o
[] = { kSecOidOrganization
, CFSTR("") };
463 const void *ca_cn
[] = { kSecOidCommonName
, cfcommon_name
};
464 CFArrayRef ca_o_dn
= CFArrayCreate(kCFAllocatorDefault
, ca_o
, 2, NULL
);
465 CFArrayRef ca_cn_dn
= CFArrayCreate(kCFAllocatorDefault
, ca_cn
, 2, NULL
);
466 const void *ca_dn_array
[2];
468 ca_dn_array
[0] = CFArrayCreate(kCFAllocatorDefault
, (const void **)&ca_o_dn
, 1, NULL
);
469 ca_dn_array
[1] = CFArrayCreate(kCFAllocatorDefault
, (const void **)&ca_cn_dn
, 1, NULL
);
471 CFArrayRef subject
= CFArrayCreate(kCFAllocatorDefault
, ca_dn_array
, 2, NULL
);
472 SecCertificateRef cert
= SecGenerateSelfSignedCertificate(subject
, certParams
, publicKey
, privateKey
);
474 CFRelease(certParams
);
479 ident
= SecIdentityCreate(kCFAllocatorDefault
, cert
, privateKey
);
485 * Cleanup and return...
491 CFRelease(cfcommon_name
);
494 CFRelease(keyParams
);
503 CFRelease(publicKey
);
506 CFRelease(publicKey
);
510 # else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */
511 int pid
, /* Process ID of command */
512 status
; /* Status of command */
513 char command
[1024], /* Command */
514 *argv
[4], /* Command-line arguments */
515 keychain
[1024], /* Keychain argument */
516 infofile
[1024]; /* Type-in information for cert */
517 cups_file_t
*fp
; /* Seed/info file */
521 * Run the "certtool" command to generate a self-signed certificate...
524 if (!cupsFileFind("certtool", getenv("PATH"), 1, command
, sizeof(command
)))
528 * Create a file with the certificate information fields...
530 * Note: This assumes that the default questions are asked by the certtool
534 if ((fp
= cupsTempFile2(infofile
, sizeof(infofile
))) == NULL
)
538 "%s\n" /* Enter key and certificate label */
539 "r\n" /* Generate RSA key pair */
540 "2048\n" /* Key size in bits */
541 "y\n" /* OK (y = yes) */
542 "b\n" /* Usage (b=signing/encryption) */
543 "s\n" /* Sign with SHA1 */
544 "y\n" /* OK (y = yes) */
545 "%s\n" /* Common name */
546 "\n" /* Country (default) */
547 "\n" /* Organization (default) */
548 "\n" /* Organizational unit (default) */
549 "\n" /* State/Province (default) */
550 "%s\n" /* Email address */
551 "y\n", /* OK (y = yes) */
552 common_name
, common_name
, "");
555 snprintf(keychain
, sizeof(keychain
), "k=%s", path
);
557 argv
[0] = "certtool";
562 posix_spawn_file_actions_t actions
; /* File actions */
564 posix_spawn_file_actions_init(&actions
);
565 posix_spawn_file_actions_addclose(&actions
, 0);
566 posix_spawn_file_actions_addopen(&actions
, 0, infofile
, O_RDONLY
, 0);
568 if (posix_spawn(&pid
, command
, &actions
, NULL
, argv
, environ
))
574 posix_spawn_file_actions_destroy(&actions
);
578 while (waitpid(pid
, &status
, 0) < 0)
588 # endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */
590 return (httpLoadCredentials(path
, credentials
, common_name
));
596 * 'httpSaveCredentials()' - Save X.509 credentials to a keychain file.
601 int /* O - -1 on error, 0 on success */
603 const char *path
, /* I - Keychain/PKCS#12 path */
604 cups_array_t
*credentials
, /* I - Credentials */
605 const char *common_name
) /* I - Common name for credentials */
616 * 'http_cdsa_read()' - Read function for the CDSA library.
619 static OSStatus
/* O - -1 on error, 0 on success */
621 SSLConnectionRef connection
, /* I - SSL/TLS connection */
622 void *data
, /* I - Data buffer */
623 size_t *dataLength
) /* IO - Number of bytes */
625 OSStatus result
; /* Return value */
626 ssize_t bytes
; /* Number of bytes read */
627 http_t
*http
; /* HTTP connection */
630 http
= (http_t
*)connection
;
635 * Make sure we have data before we read...
638 while (!_httpWait(http
, http
->wait_value
, 0))
640 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
643 http
->error
= ETIMEDOUT
;
650 bytes
= recv(http
->fd
, data
, *dataLength
, 0);
652 while (bytes
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
654 if (bytes
== *dataLength
)
661 result
= errSSLWouldBlock
;
668 result
= errSSLClosedGraceful
;
669 else if (errno
== EAGAIN
)
670 result
= errSSLWouldBlock
;
672 result
= errSSLClosedAbort
;
680 * 'http_cdsa_write()' - Write function for the CDSA library.
683 static OSStatus
/* O - -1 on error, 0 on success */
685 SSLConnectionRef connection
, /* I - SSL/TLS connection */
686 const void *data
, /* I - Data buffer */
687 size_t *dataLength
) /* IO - Number of bytes */
689 OSStatus result
; /* Return value */
690 ssize_t bytes
; /* Number of bytes read */
691 http_t
*http
; /* HTTP connection */
694 http
= (http_t
*)connection
;
698 bytes
= write(http
->fd
, data
, *dataLength
);
700 while (bytes
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
702 if (bytes
== *dataLength
)
709 result
= errSSLWouldBlock
;
716 result
= errSSLWouldBlock
;
718 result
= errSSLClosedAbort
;
726 * 'http_tls_initialize()' - Initialize the TLS stack.
730 http_tls_initialize(void)
739 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
743 http_tls_pending(http_t
*http
) /* I - HTTP connection */
745 size_t bytes
; /* Bytes that are available */
748 if (!SSLGetBufferedReadSize(http
->tls
, &bytes
))
756 * 'http_tls_read()' - Read from a SSL/TLS connection.
759 static int /* O - Bytes read */
760 http_tls_read(http_t
*http
, /* I - Connection to server */
761 char *buf
, /* I - Buffer to store data */
762 int len
) /* I - Length of buffer */
764 int result
; /* Return value */
765 OSStatus error
; /* Error info */
766 size_t processed
; /* Number of bytes processed */
769 error
= SSLRead(http
->tls
, buf
, len
, &processed
);
770 DEBUG_printf(("6http_tls_read: error=%d, processed=%d", (int)error
,
775 result
= (int)processed
;
778 case errSSLWouldBlock
:
780 result
= (int)processed
;
788 case errSSLClosedGraceful
:
791 result
= (int)processed
;
805 * 'http_tls_set_credentials()' - Set the TLS credentials.
808 static int /* O - Status of connection */
809 http_tls_set_credentials(http_t
*http
) /* I - Connection to server */
811 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
812 OSStatus error
= 0; /* Error code */
813 http_tls_credentials_t credentials
= NULL
;
814 /* TLS credentials */
817 DEBUG_printf(("7http_tls_set_credentials(%p)", http
));
820 * Prefer connection specific credentials...
823 if ((credentials
= http
->tls_credentials
) == NULL
)
824 credentials
= cg
->tls_credentials
;
828 error
= SSLSetCertificate(http
->tls
, credentials
);
829 DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d",
833 DEBUG_puts("4http_tls_set_credentials: No credentials to set.");
840 * 'http_tls_start()' - Set up SSL/TLS support on a connection.
843 static int /* O - 0 on success, -1 on failure */
844 http_tls_start(http_t
*http
) /* I - Connection to server */
846 char hostname
[256], /* Hostname */
847 *hostptr
; /* Pointer into hostname */
848 _cups_globals_t
*cg
= _cupsGlobals();
849 /* Pointer to library globals */
850 OSStatus error
; /* Error code */
851 const char *message
= NULL
;/* Error message */
852 cups_array_t
*credentials
; /* Credentials array */
853 cups_array_t
*names
; /* CUPS distinguished names */
854 CFArrayRef dn_array
; /* CF distinguished names array */
855 CFIndex count
; /* Number of credentials */
856 CFDataRef data
; /* Certificate data */
857 int i
; /* Looping var */
858 http_credential_t
*credential
; /* Credential data */
861 DEBUG_printf(("7http_tls_start(http=%p)", http
));
864 * Get the hostname to use for SSL...
867 if (httpAddrLocalhost(http
->hostaddr
))
869 strlcpy(hostname
, "localhost", sizeof(hostname
));
874 * Otherwise make sure the hostname we have does not end in a trailing dot.
877 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
878 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
883 if ((http
->tls
= SSLCreateContext(kCFAllocatorDefault
, http
->mode
== _HTTP_MODE_CLIENT
? kSSLClientSide
: kSSLServerSide
, kSSLStreamType
)) == NULL
)
885 DEBUG_puts("4http_tls_start: SSLCreateContext failed.");
886 http
->error
= errno
= ENOMEM
;
887 http
->status
= HTTP_STATUS_ERROR
;
888 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
893 error
= SSLSetConnection(http
->tls
, http
);
894 DEBUG_printf(("4http_tls_start: SSLSetConnection, error=%d", (int)error
));
898 error
= SSLSetIOFuncs(http
->tls
, http_cdsa_read
, http_cdsa_write
);
899 DEBUG_printf(("4http_tls_start: SSLSetIOFuncs, error=%d", (int)error
));
904 error
= SSLSetSessionOption(http
->tls
, kSSLSessionOptionBreakOnServerAuth
,
906 DEBUG_printf(("4http_tls_start: SSLSetSessionOption, error=%d",
912 if (cg
->client_cert_cb
)
914 error
= SSLSetSessionOption(http
->tls
,
915 kSSLSessionOptionBreakOnCertRequested
, true);
916 DEBUG_printf(("4http_tls_start: kSSLSessionOptionBreakOnCertRequested, "
917 "error=%d", (int)error
));
921 error
= http_tls_set_credentials(http
);
922 DEBUG_printf(("4http_tls_start: http_tls_set_credentials, error=%d",
928 * Let the server know which hostname/domain we are trying to connect to
929 * in case it wants to serve up a certificate with a matching common name.
934 error
= SSLSetPeerDomainName(http
->tls
, hostname
, strlen(hostname
));
936 DEBUG_printf(("4http_tls_start: SSLSetPeerDomainName, error=%d",
942 int done
= 0; /* Are we done yet? */
944 while (!error
&& !done
)
946 error
= SSLHandshake(http
->tls
);
948 DEBUG_printf(("4http_tls_start: SSLHandshake returned %d.", (int)error
));
956 case errSSLWouldBlock
:
957 error
= noErr
; /* Force a retry */
958 usleep(1000); /* in 1 millisecond */
961 case errSSLServerAuthCompleted
:
963 if (cg
->server_cert_cb
)
965 error
= httpCopyCredentials(http
, &credentials
);
968 error
= (cg
->server_cert_cb
)(http
, http
->tls
, credentials
,
969 cg
->server_cert_data
);
970 httpFreeCredentials(credentials
);
973 DEBUG_printf(("4http_tls_start: Server certificate callback "
974 "returned %d.", (int)error
));
978 case errSSLClientCertRequested
:
981 if (cg
->client_cert_cb
)
984 if (!(error
= SSLCopyDistinguishedNames(http
->tls
, &dn_array
)) &&
987 if ((names
= cupsArrayNew(NULL
, NULL
)) != NULL
)
989 for (i
= 0, count
= CFArrayGetCount(dn_array
); i
< count
; i
++)
991 data
= (CFDataRef
)CFArrayGetValueAtIndex(dn_array
, i
);
993 if ((credential
= malloc(sizeof(*credential
))) != NULL
)
995 credential
->datalen
= CFDataGetLength(data
);
996 if ((credential
->data
= malloc(credential
->datalen
)))
998 memcpy((void *)credential
->data
, CFDataGetBytePtr(data
),
999 credential
->datalen
);
1000 cupsArrayAdd(names
, credential
);
1008 CFRelease(dn_array
);
1013 error
= (cg
->client_cert_cb
)(http
, http
->tls
, names
,
1014 cg
->client_cert_data
);
1016 DEBUG_printf(("4http_tls_start: Client certificate callback "
1017 "returned %d.", (int)error
));
1020 httpFreeCredentials(names
);
1024 case errSSLUnknownRootCert
:
1025 message
= _("Unable to establish a secure connection to host "
1026 "(untrusted certificate).");
1029 case errSSLNoRootCert
:
1030 message
= _("Unable to establish a secure connection to host "
1031 "(self-signed certificate).");
1034 case errSSLCertExpired
:
1035 message
= _("Unable to establish a secure connection to host "
1036 "(expired certificate).");
1039 case errSSLCertNotYetValid
:
1040 message
= _("Unable to establish a secure connection to host "
1041 "(certificate not yet valid).");
1044 case errSSLHostNameMismatch
:
1045 message
= _("Unable to establish a secure connection to host "
1046 "(host name mismatch).");
1049 case errSSLXCertChainInvalid
:
1050 message
= _("Unable to establish a secure connection to host "
1051 "(certificate chain invalid).");
1054 case errSSLConnectionRefused
:
1055 message
= _("Unable to establish a secure connection to host "
1056 "(peer dropped connection before responding).");
1067 http
->error
= error
;
1068 http
->status
= HTTP_STATUS_ERROR
;
1069 errno
= ECONNREFUSED
;
1071 CFRelease(http
->tls
);
1075 * If an error string wasn't set by the callbacks use a generic one...
1079 #ifdef HAVE_CSSMERRORSTRING
1080 message
= cssmErrorString(error
);
1082 message
= _("Unable to establish a secure connection to host.");
1083 #endif /* HAVE_CSSMERRORSTRING */
1085 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, message
, 1);
1095 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
1099 http_tls_stop(http_t
*http
) /* I - Connection to server */
1101 while (SSLClose(http
->tls
) == errSSLWouldBlock
)
1104 CFRelease(http
->tls
);
1106 if (http
->tls_credentials
)
1107 CFRelease(http
->tls_credentials
);
1110 http
->tls_credentials
= NULL
;
1115 * 'http_tls_write()' - Write to a SSL/TLS connection.
1118 static int /* O - Bytes written */
1119 http_tls_write(http_t
*http
, /* I - Connection to server */
1120 const char *buf
, /* I - Buffer holding data */
1121 int len
) /* I - Length of buffer */
1123 ssize_t result
; /* Return value */
1124 OSStatus error
; /* Error info */
1125 size_t processed
; /* Number of bytes processed */
1128 DEBUG_printf(("2http_tls_write(http=%p, buf=%p, len=%d)", http
, buf
, len
));
1130 error
= SSLWrite(http
->tls
, buf
, len
, &processed
);
1135 result
= (int)processed
;
1138 case errSSLWouldBlock
:
1141 result
= (int)processed
;
1150 case errSSLClosedGraceful
:
1154 result
= (int)processed
;
1164 DEBUG_printf(("3http_tls_write: Returning %d.", (int)result
));
1166 return ((int)result
);
1172 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
1175 int /* O - 1 on success, 0 on error */
1176 cupsdEndTLS(cupsd_client_t
*con
) /* I - Client connection */
1178 while (SSLClose(con
->http
.tls
) == errSSLWouldBlock
)
1181 CFRelease(con
->http
.tls
);
1182 con
->http
.tls
= NULL
;
1184 if (con
->http
.tls_credentials
)
1185 CFRelease(con
->http
.tls_credentials
);
1192 * 'cupsdStartTLS()' - Start a secure session with the client.
1195 int /* O - 1 on success, 0 on error */
1196 cupsdStartTLS(cupsd_client_t
*con
) /* I - Client connection */
1198 OSStatus error
= 0; /* Error code */
1199 SecTrustRef peerTrust
; /* Peer certificates */
1202 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Client %d] Encrypting connection.",
1205 con
->http
.tls_credentials
= copy_cdsa_certificate(con
);
1207 if (!con
->http
.tls_credentials
)
1210 * No keychain (yet), make a self-signed certificate...
1213 if (make_certificate(con
))
1214 con
->http
.tls_credentials
= copy_cdsa_certificate(con
);
1217 if (!con
->http
.tls_credentials
)
1219 cupsdLogMessage(CUPSD_LOG_ERROR
,
1220 "Could not find signing key in keychain \"%s\"",
1222 error
= errSSLBadConfiguration
;
1226 con
->http
.tls
= SSLCreateContext(kCFAllocatorDefault
, kSSLServerSide
,
1230 error
= SSLSetIOFuncs(con
->http
.tls
, http_cdsa_read
, http_cdsa_write
);
1233 error
= SSLSetConnection(con
->http
.tls
, HTTP(con
));
1236 error
= SSLSetCertificate(con
->http
.tls
, con
->http
.tls_credentials
);
1241 * Perform SSL/TLS handshake
1244 while ((error
= SSLHandshake(con
->http
.tls
)) == errSSLWouldBlock
)
1250 cupsdLogMessage(CUPSD_LOG_ERROR
,
1251 "Unable to encrypt connection from %s - %s (%d)",
1252 con
->http
.hostname
, cssmErrorString(error
), (int)error
);
1254 con
->http
.error
= error
;
1255 con
->http
.status
= HTTP_ERROR
;
1259 CFRelease(con
->http
.tls
);
1260 con
->http
.tls
= NULL
;
1263 if (con
->http
.tls_credentials
)
1265 CFRelease(con
->http
.tls_credentials
);
1266 con
->http
.tls_credentials
= NULL
;
1272 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Connection from %s now encrypted.",
1273 con
->http
.hostname
);
1275 if (!SSLCopyPeerTrust(con
->http
.tls
, &peerTrust
) && peerTrust
)
1277 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Received %d peer certificates.",
1278 (int)SecTrustGetCertificateCount(peerTrust
));
1279 CFRelease(peerTrust
);
1282 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Received NO peer certificates.");