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.
23 //static CFArrayRef copy_cdsa_certificate(cupsd_client_t *con);
24 //static int make_certificate(cupsd_client_t *con);
26 static OSStatus
http_cdsa_read(SSLConnectionRef connection
, void *data
,
28 static OSStatus
http_cdsa_write(SSLConnectionRef connection
, const void *data
,
34 * 'httpCopyCredentials()' - Copy the credentials associated with the peer in
35 * an encrypted connection.
37 * @since CUPS 1.5/OS X 10.7@
40 int /* O - Status of call (0 = success) */
42 http_t
*http
, /* I - Connection to server */
43 cups_array_t
**credentials
) /* O - Array of credentials */
45 OSStatus error
; /* Error code */
46 SecTrustRef peerTrust
; /* Peer trust reference */
47 CFIndex count
; /* Number of credentials */
48 SecCertificateRef secCert
; /* Certificate reference */
49 CFDataRef data
; /* Certificate data */
50 int i
; /* Looping var */
56 if (!http
|| !http
->tls
|| !credentials
)
59 if (!(error
= SSLCopyPeerTrust(http
->tls
, &peerTrust
)) && peerTrust
)
61 if ((*credentials
= cupsArrayNew(NULL
, NULL
)) != NULL
)
63 count
= SecTrustGetCertificateCount(peerTrust
);
65 for (i
= 0; i
< count
; i
++)
67 secCert
= SecTrustGetCertificateAtIndex(peerTrust
, i
);
68 if ((data
= SecCertificateCopyData(secCert
)))
70 httpAddCredential(*credentials
, CFDataGetBytePtr(data
),
71 CFDataGetLength(data
));
85 * '_httpCreateCredentials()' - Create credentials in the internal format.
88 http_tls_credentials_t
/* O - Internal credentials */
89 _httpCreateCredentials(
90 cups_array_t
*credentials
) /* I - Array of credentials */
92 CFMutableArrayRef peerCerts
; /* Peer credentials reference */
93 SecCertificateRef secCert
; /* Certificate reference */
94 CFDataRef data
; /* Credential data reference */
95 http_credential_t
*credential
; /* Credential data */
101 if ((peerCerts
= CFArrayCreateMutable(kCFAllocatorDefault
,
102 cupsArrayCount(credentials
),
103 &kCFTypeArrayCallBacks
)) == NULL
)
106 for (credential
= (http_credential_t
*)cupsArrayFirst(credentials
);
108 credential
= (http_credential_t
*)cupsArrayNext(credentials
))
110 if ((data
= CFDataCreate(kCFAllocatorDefault
, credential
->data
,
111 credential
->datalen
)))
113 if ((secCert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
))
116 CFArrayAppendValue(peerCerts
, secCert
);
129 * '_httpFreeCredentials()' - Free internal credentials.
133 _httpFreeCredentials(
134 http_tls_credentials_t credentials
) /* I - Internal credentials */
139 CFRelease(credentials
);
144 * 'http_cdsa_read()' - Read function for the CDSA library.
147 static OSStatus
/* O - -1 on error, 0 on success */
149 SSLConnectionRef connection
, /* I - SSL/TLS connection */
150 void *data
, /* I - Data buffer */
151 size_t *dataLength
) /* IO - Number of bytes */
153 OSStatus result
; /* Return value */
154 ssize_t bytes
; /* Number of bytes read */
155 http_t
*http
; /* HTTP connection */
158 http
= (http_t
*)connection
;
163 * Make sure we have data before we read...
166 while (!_httpWait(http
, http
->wait_value
, 0))
168 if (http
->timeout_cb
&& (*http
->timeout_cb
)(http
, http
->timeout_data
))
171 http
->error
= ETIMEDOUT
;
178 bytes
= recv(http
->fd
, data
, *dataLength
, 0);
180 while (bytes
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
182 if (bytes
== *dataLength
)
189 result
= errSSLWouldBlock
;
196 result
= errSSLClosedGraceful
;
197 else if (errno
== EAGAIN
)
198 result
= errSSLWouldBlock
;
200 result
= errSSLClosedAbort
;
208 * 'http_cdsa_write()' - Write function for the CDSA library.
211 static OSStatus
/* O - -1 on error, 0 on success */
213 SSLConnectionRef connection
, /* I - SSL/TLS connection */
214 const void *data
, /* I - Data buffer */
215 size_t *dataLength
) /* IO - Number of bytes */
217 OSStatus result
; /* Return value */
218 ssize_t bytes
; /* Number of bytes read */
219 http_t
*http
; /* HTTP connection */
222 http
= (http_t
*)connection
;
226 bytes
= write(http
->fd
, data
, *dataLength
);
228 while (bytes
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
230 if (bytes
== *dataLength
)
237 result
= errSSLWouldBlock
;
244 result
= errSSLWouldBlock
;
246 result
= errSSLClosedAbort
;
254 * 'http_tls_initialize()' - Initialize the TLS stack.
258 http_tls_initialize(void)
267 * 'http_tls_pending()' - Return the number of pending TLS-encrypted bytes.
271 http_tls_pending(http_t
*http
) /* I - HTTP connection */
273 size_t bytes
; /* Bytes that are available */
276 if (!SSLGetBufferedReadSize(http
->tls
, &bytes
))
284 * 'http_tls_read()' - Read from a SSL/TLS connection.
287 static int /* O - Bytes read */
288 http_tls_read(http_t
*http
, /* I - Connection to server */
289 char *buf
, /* I - Buffer to store data */
290 int len
) /* I - Length of buffer */
292 int result
; /* Return value */
293 OSStatus error
; /* Error info */
294 size_t processed
; /* Number of bytes processed */
297 error
= SSLRead(http
->tls
, buf
, len
, &processed
);
298 DEBUG_printf(("6http_tls_read: error=%d, processed=%d", (int)error
,
303 result
= (int)processed
;
306 case errSSLWouldBlock
:
308 result
= (int)processed
;
316 case errSSLClosedGraceful
:
319 result
= (int)processed
;
333 * 'http_tls_set_credentials()' - Set the TLS credentials.
336 static int /* O - Status of connection */
337 http_tls_set_credentials(http_t
*http
) /* I - Connection to server */
339 _cups_globals_t
*cg
= _cupsGlobals(); /* Pointer to library globals */
340 OSStatus error
= 0; /* Error code */
341 http_tls_credentials_t credentials
= NULL
;
342 /* TLS credentials */
345 DEBUG_printf(("7http_tls_set_credentials(%p)", http
));
348 * Prefer connection specific credentials...
351 if ((credentials
= http
->tls_credentials
) == NULL
)
352 credentials
= cg
->tls_credentials
;
356 error
= SSLSetCertificate(http
->tls
, credentials
);
357 DEBUG_printf(("4http_tls_set_credentials: SSLSetCertificate, error=%d",
361 DEBUG_puts("4http_tls_set_credentials: No credentials to set.");
368 * 'http_tls_start()' - Set up SSL/TLS support on a connection.
371 static int /* O - 0 on success, -1 on failure */
372 http_tls_start(http_t
*http
) /* I - Connection to server */
374 char hostname
[256], /* Hostname */
375 *hostptr
; /* Pointer into hostname */
376 _cups_globals_t
*cg
= _cupsGlobals();
377 /* Pointer to library globals */
378 OSStatus error
; /* Error code */
379 const char *message
= NULL
;/* Error message */
380 cups_array_t
*credentials
; /* Credentials array */
381 cups_array_t
*names
; /* CUPS distinguished names */
382 CFArrayRef dn_array
; /* CF distinguished names array */
383 CFIndex count
; /* Number of credentials */
384 CFDataRef data
; /* Certificate data */
385 int i
; /* Looping var */
386 http_credential_t
*credential
; /* Credential data */
389 DEBUG_printf(("7http_tls_start(http=%p)", http
));
392 * Get the hostname to use for SSL...
395 if (httpAddrLocalhost(http
->hostaddr
))
397 strlcpy(hostname
, "localhost", sizeof(hostname
));
402 * Otherwise make sure the hostname we have does not end in a trailing dot.
405 strlcpy(hostname
, http
->hostname
, sizeof(hostname
));
406 if ((hostptr
= hostname
+ strlen(hostname
) - 1) >= hostname
&&
411 if ((http
->tls
= SSLCreateContext(kCFAllocatorDefault
, kSSLClientSide
,
412 kSSLStreamType
)) == NULL
)
414 DEBUG_puts("4http_tls_start: SSLCreateContext failed.");
415 http
->error
= errno
= ENOMEM
;
416 http
->status
= HTTP_STATUS_ERROR
;
417 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
422 error
= SSLSetConnection(http
->tls
, http
);
423 DEBUG_printf(("4http_tls_start: SSLSetConnection, error=%d", (int)error
));
427 error
= SSLSetIOFuncs(http
->tls
, http_cdsa_read
, http_cdsa_write
);
428 DEBUG_printf(("4http_tls_start: SSLSetIOFuncs, error=%d", (int)error
));
433 error
= SSLSetSessionOption(http
->tls
, kSSLSessionOptionBreakOnServerAuth
,
435 DEBUG_printf(("4http_tls_start: SSLSetSessionOption, error=%d",
441 if (cg
->client_cert_cb
)
443 error
= SSLSetSessionOption(http
->tls
,
444 kSSLSessionOptionBreakOnCertRequested
, true);
445 DEBUG_printf(("4http_tls_start: kSSLSessionOptionBreakOnCertRequested, "
446 "error=%d", (int)error
));
450 error
= http_tls_set_credentials(http
);
451 DEBUG_printf(("4http_tls_start: http_tls_set_credentials, error=%d",
457 * Let the server know which hostname/domain we are trying to connect to
458 * in case it wants to serve up a certificate with a matching common name.
463 error
= SSLSetPeerDomainName(http
->tls
, hostname
, strlen(hostname
));
465 DEBUG_printf(("4http_tls_start: SSLSetPeerDomainName, error=%d",
471 int done
= 0; /* Are we done yet? */
473 while (!error
&& !done
)
475 error
= SSLHandshake(http
->tls
);
477 DEBUG_printf(("4http_tls_start: SSLHandshake returned %d.", (int)error
));
485 case errSSLWouldBlock
:
486 error
= noErr
; /* Force a retry */
487 usleep(1000); /* in 1 millisecond */
490 case errSSLServerAuthCompleted
:
492 if (cg
->server_cert_cb
)
494 error
= httpCopyCredentials(http
, &credentials
);
497 error
= (cg
->server_cert_cb
)(http
, http
->tls
, credentials
,
498 cg
->server_cert_data
);
499 httpFreeCredentials(credentials
);
502 DEBUG_printf(("4http_tls_start: Server certificate callback "
503 "returned %d.", (int)error
));
507 case errSSLClientCertRequested
:
510 if (cg
->client_cert_cb
)
513 if (!(error
= SSLCopyDistinguishedNames(http
->tls
, &dn_array
)) &&
516 if ((names
= cupsArrayNew(NULL
, NULL
)) != NULL
)
518 for (i
= 0, count
= CFArrayGetCount(dn_array
); i
< count
; i
++)
520 data
= (CFDataRef
)CFArrayGetValueAtIndex(dn_array
, i
);
522 if ((credential
= malloc(sizeof(*credential
))) != NULL
)
524 credential
->datalen
= CFDataGetLength(data
);
525 if ((credential
->data
= malloc(credential
->datalen
)))
527 memcpy((void *)credential
->data
, CFDataGetBytePtr(data
),
528 credential
->datalen
);
529 cupsArrayAdd(names
, credential
);
542 error
= (cg
->client_cert_cb
)(http
, http
->tls
, names
,
543 cg
->client_cert_data
);
545 DEBUG_printf(("4http_tls_start: Client certificate callback "
546 "returned %d.", (int)error
));
549 httpFreeCredentials(names
);
553 case errSSLUnknownRootCert
:
554 message
= _("Unable to establish a secure connection to host "
555 "(untrusted certificate).");
558 case errSSLNoRootCert
:
559 message
= _("Unable to establish a secure connection to host "
560 "(self-signed certificate).");
563 case errSSLCertExpired
:
564 message
= _("Unable to establish a secure connection to host "
565 "(expired certificate).");
568 case errSSLCertNotYetValid
:
569 message
= _("Unable to establish a secure connection to host "
570 "(certificate not yet valid).");
573 case errSSLHostNameMismatch
:
574 message
= _("Unable to establish a secure connection to host "
575 "(host name mismatch).");
578 case errSSLXCertChainInvalid
:
579 message
= _("Unable to establish a secure connection to host "
580 "(certificate chain invalid).");
583 case errSSLConnectionRefused
:
584 message
= _("Unable to establish a secure connection to host "
585 "(peer dropped connection before responding).");
597 http
->status
= HTTP_STATUS_ERROR
;
598 errno
= ECONNREFUSED
;
600 CFRelease(http
->tls
);
604 * If an error string wasn't set by the callbacks use a generic one...
608 #ifdef HAVE_CSSMERRORSTRING
609 message
= cssmErrorString(error
);
611 message
= _("Unable to establish a secure connection to host.");
612 #endif /* HAVE_CSSMERRORSTRING */
614 _cupsSetError(IPP_STATUS_ERROR_CUPS_PKI
, message
, 1);
624 * 'http_tls_stop()' - Shut down SSL/TLS on a connection.
628 http_tls_stop(http_t
*http
) /* I - Connection to server */
630 while (SSLClose(http
->tls
) == errSSLWouldBlock
)
633 CFRelease(http
->tls
);
635 if (http
->tls_credentials
)
636 CFRelease(http
->tls_credentials
);
639 http
->tls_credentials
= NULL
;
644 * 'http_tls_write()' - Write to a SSL/TLS connection.
647 static int /* O - Bytes written */
648 http_tls_write(http_t
*http
, /* I - Connection to server */
649 const char *buf
, /* I - Buffer holding data */
650 int len
) /* I - Length of buffer */
652 ssize_t result
; /* Return value */
653 OSStatus error
; /* Error info */
654 size_t processed
; /* Number of bytes processed */
657 DEBUG_printf(("2http_tls_write(http=%p, buf=%p, len=%d)", http
, buf
, len
));
659 error
= SSLWrite(http
->tls
, buf
, len
, &processed
);
664 result
= (int)processed
;
667 case errSSLWouldBlock
:
670 result
= (int)processed
;
679 case errSSLClosedGraceful
:
683 result
= (int)processed
;
693 DEBUG_printf(("3http_tls_write: Returning %d.", (int)result
));
695 return ((int)result
);
701 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
704 int /* O - 1 on success, 0 on error */
705 cupsdEndTLS(cupsd_client_t
*con
) /* I - Client connection */
707 while (SSLClose(con
->http
.tls
) == errSSLWouldBlock
)
710 CFRelease(con
->http
.tls
);
711 con
->http
.tls
= NULL
;
713 if (con
->http
.tls_credentials
)
714 CFRelease(con
->http
.tls_credentials
);
721 * 'cupsdStartTLS()' - Start a secure session with the client.
724 int /* O - 1 on success, 0 on error */
725 cupsdStartTLS(cupsd_client_t
*con
) /* I - Client connection */
727 OSStatus error
= 0; /* Error code */
728 SecTrustRef peerTrust
; /* Peer certificates */
731 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Client %d] Encrypting connection.",
734 con
->http
.tls_credentials
= copy_cdsa_certificate(con
);
736 if (!con
->http
.tls_credentials
)
739 * No keychain (yet), make a self-signed certificate...
742 if (make_certificate(con
))
743 con
->http
.tls_credentials
= copy_cdsa_certificate(con
);
746 if (!con
->http
.tls_credentials
)
748 cupsdLogMessage(CUPSD_LOG_ERROR
,
749 "Could not find signing key in keychain \"%s\"",
751 error
= errSSLBadConfiguration
;
755 con
->http
.tls
= SSLCreateContext(kCFAllocatorDefault
, kSSLServerSide
,
759 error
= SSLSetIOFuncs(con
->http
.tls
, http_cdsa_read
, http_cdsa_write
);
762 error
= SSLSetConnection(con
->http
.tls
, HTTP(con
));
765 error
= SSLSetCertificate(con
->http
.tls
, con
->http
.tls_credentials
);
770 * Perform SSL/TLS handshake
773 while ((error
= SSLHandshake(con
->http
.tls
)) == errSSLWouldBlock
)
779 cupsdLogMessage(CUPSD_LOG_ERROR
,
780 "Unable to encrypt connection from %s - %s (%d)",
781 con
->http
.hostname
, cssmErrorString(error
), (int)error
);
783 con
->http
.error
= error
;
784 con
->http
.status
= HTTP_ERROR
;
788 CFRelease(con
->http
.tls
);
789 con
->http
.tls
= NULL
;
792 if (con
->http
.tls_credentials
)
794 CFRelease(con
->http
.tls_credentials
);
795 con
->http
.tls_credentials
= NULL
;
801 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Connection from %s now encrypted.",
804 if (!SSLCopyPeerTrust(con
->http
.tls
, &peerTrust
) && peerTrust
)
806 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Received %d peer certificates.",
807 (int)SecTrustGetCertificateCount(peerTrust
));
808 CFRelease(peerTrust
);
811 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Received NO peer certificates.");
818 * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System
822 static CFArrayRef
/* O - Array of certificates */
823 copy_cdsa_certificate(
824 cupsd_client_t
*con
) /* I - Client connection */
826 OSStatus err
; /* Error info */
827 SecKeychainRef keychain
= NULL
;/* Keychain reference */
828 SecIdentitySearchRef search
= NULL
; /* Search reference */
829 SecIdentityRef identity
= NULL
;/* Identity */
830 CFArrayRef certificates
= NULL
;
831 /* Certificate array */
832 SecPolicyRef policy
= NULL
; /* Policy ref */
833 CFStringRef servername
= NULL
;
835 CFMutableDictionaryRef query
= NULL
; /* Query qualifiers */
836 CFArrayRef list
= NULL
; /* Keychain list */
837 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
838 char localname
[1024];/* Local hostname */
839 # endif /* HAVE_DNSSD || HAVE_AVAHI */
842 cupsdLogMessage(CUPSD_LOG_DEBUG
,
843 "copy_cdsa_certificate: Looking for certs for \"%s\".",
846 if ((err
= SecKeychainOpen(ServerCertificate
, &keychain
)))
848 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot open keychain \"%s\" - %s (%d)",
849 ServerCertificate
, cssmErrorString(err
), (int)err
);
853 servername
= CFStringCreateWithCString(kCFAllocatorDefault
, con
->servername
,
854 kCFStringEncodingUTF8
);
856 policy
= SecPolicyCreateSSL(1, servername
);
859 CFRelease(servername
);
863 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create ssl policy reference");
867 if (!(query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
868 &kCFTypeDictionaryKeyCallBacks
,
869 &kCFTypeDictionaryValueCallBacks
)))
871 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create query dictionary");
875 list
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&keychain
, 1,
876 &kCFTypeArrayCallBacks
);
878 CFDictionaryAddValue(query
, kSecClass
, kSecClassIdentity
);
879 CFDictionaryAddValue(query
, kSecMatchPolicy
, policy
);
880 CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
);
881 CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitOne
);
882 CFDictionaryAddValue(query
, kSecMatchSearchList
, list
);
886 err
= SecItemCopyMatching(query
, (CFTypeRef
*)&identity
);
888 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
889 if (err
&& DNSSDHostName
)
892 * Search for the connection server name failed; try the DNS-SD .local
893 * hostname instead...
896 snprintf(localname
, sizeof(localname
), "%s.local", DNSSDHostName
);
898 cupsdLogMessage(CUPSD_LOG_DEBUG
,
899 "copy_cdsa_certificate: Looking for certs for \"%s\".",
902 servername
= CFStringCreateWithCString(kCFAllocatorDefault
, localname
,
903 kCFStringEncodingUTF8
);
907 policy
= SecPolicyCreateSSL(1, servername
);
910 CFRelease(servername
);
914 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create ssl policy reference");
918 CFDictionarySetValue(query
, kSecMatchPolicy
, policy
);
920 err
= SecItemCopyMatching(query
, (CFTypeRef
*)&identity
);
922 # endif /* HAVE_DNSSD || HAVE_AVAHI */
926 cupsdLogMessage(CUPSD_LOG_DEBUG
,
927 "Cannot find signing key in keychain \"%s\": %s (%d)",
928 ServerCertificate
, cssmErrorString(err
), (int)err
);
932 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
934 cupsdLogMessage(CUPSD_LOG_ERROR
, "SecIdentity CFTypeID failure.");
938 if ((certificates
= CFArrayCreate(NULL
, (const void **)&identity
,
939 1, &kCFTypeArrayCallBacks
)) == NULL
)
941 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create certificate array");
959 return (certificates
);
964 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
967 static int /* O - 1 on success, 0 on failure */
968 make_certificate(cupsd_client_t
*con
) /* I - Client connection */
970 # ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE
971 int status
= 0; /* Return status */
972 OSStatus err
; /* Error code (if any) */
973 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
974 char localname
[1024];/* Local hostname */
975 # endif /* HAVE_DNSSD || HAVE_AVAHI */
976 const char *servername
; /* Name of server in cert */
977 CFStringRef cfservername
= NULL
;
978 /* CF string for server name */
979 SecIdentityRef ident
= NULL
; /* Identity */
980 SecKeyRef publicKey
= NULL
,
984 CFMutableDictionaryRef keyParams
= NULL
;
985 /* Key generation parameters */
988 cupsdLogMessage(CUPSD_LOG_INFO
,
989 "Generating SSL server key and certificate.");
991 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
992 if (con
->servername
&& isdigit(con
->servername
[0] & 255) && DNSSDHostName
)
994 snprintf(localname
, sizeof(localname
), "%s.local", DNSSDHostName
);
995 servername
= localname
;
998 # endif /* HAVE_DNSSD || HAVE_AVAHI */
999 servername
= con
->servername
;
1001 cfservername
= CFStringCreateWithCString(kCFAllocatorDefault
, servername
,
1002 kCFStringEncodingUTF8
);
1007 * Create a public/private key pair...
1010 keyParams
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1011 &kCFTypeDictionaryKeyCallBacks
,
1012 &kCFTypeDictionaryValueCallBacks
);
1016 CFDictionaryAddValue(keyParams
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
1017 CFDictionaryAddValue(keyParams
, kSecAttrKeySizeInBits
, CFSTR("2048"));
1018 CFDictionaryAddValue(keyParams
, kSecAttrLabel
,
1019 CFSTR("CUPS Self-Signed Certificate"));
1021 err
= SecKeyGeneratePair(keyParams
, &publicKey
, &privateKey
);
1024 cupsdLogMessage(CUPSD_LOG_DEBUG
, "SecKeyGeneratePair returned %ld.",
1030 * Create a self-signed certificate using the public/private key pair...
1033 CFIndex usageInt
= kSecKeyUsageAll
;
1034 CFNumberRef usage
= CFNumberCreate(alloc
, kCFNumberCFIndexType
, &usageInt
);
1035 CFDictionaryRef certParams
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
1036 kSecCSRBasicContraintsPathLen
, CFINT(0),
1037 kSecSubjectAltName
, cfservername
,
1038 kSecCertificateKeyUsage
, usage
,
1042 const void *ca_o
[] = { kSecOidOrganization
, CFSTR("") };
1043 const void *ca_cn
[] = { kSecOidCommonName
, cfservername
};
1044 CFArrayRef ca_o_dn
= CFArrayCreate(kCFAllocatorDefault
, ca_o
, 2, NULL
);
1045 CFArrayRef ca_cn_dn
= CFArrayCreate(kCFAllocatorDefault
, ca_cn
, 2, NULL
);
1046 const void *ca_dn_array
[2];
1048 ca_dn_array
[0] = CFArrayCreate(kCFAllocatorDefault
, (const void **)&ca_o_dn
,
1050 ca_dn_array
[1] = CFArrayCreate(kCFAllocatorDefault
, (const void **)&ca_cn_dn
,
1053 CFArrayRef subject
= CFArrayCreate(kCFAllocatorDefault
, ca_dn_array
, 2,
1055 SecCertificateRef cert
= SecGenerateSelfSignedCertificate(subject
, certParams
,
1059 CFRelease(certParams
);
1063 cupsdLogMessage(CUPSD_LOG_DEBUG
, "SecGenerateSelfSignedCertificate failed.");
1067 ident
= SecIdentityCreate(kCFAllocatorDefault
, cert
, privateKey
);
1070 cupsdLogMessage(CUPSD_LOG_INFO
,
1071 "Created SSL server certificate file \"%s\".",
1075 * Cleanup and return...
1081 CFRelease(cfservername
);
1084 CFRelease(keyParams
);
1093 CFRelease(publicKey
);
1096 CFRelease(publicKey
);
1099 cupsdLogMessage(CUPSD_LOG_ERROR
,
1100 "Unable to create SSL server key and certificate.");
1104 # else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */
1105 int pid
, /* Process ID of command */
1106 status
; /* Status of command */
1107 char command
[1024], /* Command */
1108 *argv
[4], /* Command-line arguments */
1109 *envp
[MAX_ENV
+ 1], /* Environment variables */
1110 keychain
[1024], /* Keychain argument */
1111 infofile
[1024], /* Type-in information for cert */
1112 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1113 localname
[1024], /* Local hostname */
1114 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1115 *servername
; /* Name of server in cert */
1116 cups_file_t
*fp
; /* Seed/info file */
1117 int infofd
; /* Info file descriptor */
1120 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1121 if (con
->servername
&& isdigit(con
->servername
[0] & 255) && DNSSDHostName
)
1123 snprintf(localname
, sizeof(localname
), "%s.local", DNSSDHostName
);
1124 servername
= localname
;
1127 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1128 servername
= con
->servername
;
1131 * Run the "certtool" command to generate a self-signed certificate...
1134 if (!cupsFileFind("certtool", getenv("PATH"), 1, command
, sizeof(command
)))
1136 cupsdLogMessage(CUPSD_LOG_ERROR
,
1137 "No SSL certificate and certtool command not found.");
1142 * Create a file with the certificate information fields...
1144 * Note: This assumes that the default questions are asked by the certtool
1148 if ((fp
= cupsTempFile2(infofile
, sizeof(infofile
))) == NULL
)
1150 cupsdLogMessage(CUPSD_LOG_ERROR
,
1151 "Unable to create certificate information file %s - %s",
1152 infofile
, strerror(errno
));
1157 "%s\n" /* Enter key and certificate label */
1158 "r\n" /* Generate RSA key pair */
1159 "2048\n" /* Key size in bits */
1160 "y\n" /* OK (y = yes) */
1161 "b\n" /* Usage (b=signing/encryption) */
1162 "s\n" /* Sign with SHA1 */
1163 "y\n" /* OK (y = yes) */
1164 "%s\n" /* Common name */
1165 "\n" /* Country (default) */
1166 "\n" /* Organization (default) */
1167 "\n" /* Organizational unit (default) */
1168 "\n" /* State/Province (default) */
1169 "%s\n" /* Email address */
1170 "y\n", /* OK (y = yes) */
1171 servername
, servername
, ServerAdmin
);
1174 cupsdLogMessage(CUPSD_LOG_INFO
,
1175 "Generating SSL server key and certificate.");
1177 snprintf(keychain
, sizeof(keychain
), "k=%s", ServerCertificate
);
1179 argv
[0] = "certtool";
1184 cupsdLoadEnv(envp
, MAX_ENV
);
1186 infofd
= open(infofile
, O_RDONLY
);
1188 if (!cupsdStartProcess(command
, argv
, envp
, infofd
, -1, -1, -1, -1, 1, NULL
,
1199 while (waitpid(pid
, &status
, 0) < 0)
1206 cupsdFinishProcess(pid
, command
, sizeof(command
), NULL
);
1210 if (WIFEXITED(status
))
1211 cupsdLogMessage(CUPSD_LOG_ERROR
,
1212 "Unable to create SSL server key and certificate - "
1213 "the certtool command stopped with status %d.",
1214 WEXITSTATUS(status
));
1216 cupsdLogMessage(CUPSD_LOG_ERROR
,
1217 "Unable to create SSL server key and certificate - "
1218 "the certtool command crashed on signal %d.",
1223 cupsdLogMessage(CUPSD_LOG_INFO
,
1224 "Created SSL server certificate file \"%s\".",
1229 # endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */