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_set_credentials(http
);
451 DEBUG_printf(("4http_tls_start: http_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
);
700 * 'cupsdEndTLS()' - Shutdown a secure session with the client.
703 int /* O - 1 on success, 0 on error */
704 cupsdEndTLS(cupsd_client_t
*con
) /* I - Client connection */
706 while (SSLClose(con
->http
.tls
) == errSSLWouldBlock
)
709 CFRelease(con
->http
.tls
);
710 con
->http
.tls
= NULL
;
712 if (con
->http
.tls_credentials
)
713 CFRelease(con
->http
.tls_credentials
);
720 * 'cupsdStartTLS()' - Start a secure session with the client.
723 int /* O - 1 on success, 0 on error */
724 cupsdStartTLS(cupsd_client_t
*con
) /* I - Client connection */
726 OSStatus error
= 0; /* Error code */
727 SecTrustRef peerTrust
; /* Peer certificates */
730 cupsdLogMessage(CUPSD_LOG_DEBUG
, "[Client %d] Encrypting connection.",
733 con
->http
.tls_credentials
= copy_cdsa_certificate(con
);
735 if (!con
->http
.tls_credentials
)
738 * No keychain (yet), make a self-signed certificate...
741 if (make_certificate(con
))
742 con
->http
.tls_credentials
= copy_cdsa_certificate(con
);
745 if (!con
->http
.tls_credentials
)
747 cupsdLogMessage(CUPSD_LOG_ERROR
,
748 "Could not find signing key in keychain \"%s\"",
750 error
= errSSLBadConfiguration
;
754 con
->http
.tls
= SSLCreateContext(kCFAllocatorDefault
, kSSLServerSide
,
758 error
= SSLSetIOFuncs(con
->http
.tls
, http_cdsa_read
, http_cdsa_write
);
761 error
= SSLSetConnection(con
->http
.tls
, HTTP(con
));
764 error
= SSLSetCertificate(con
->http
.tls
, con
->http
.tls_credentials
);
769 * Perform SSL/TLS handshake
772 while ((error
= SSLHandshake(con
->http
.tls
)) == errSSLWouldBlock
)
778 cupsdLogMessage(CUPSD_LOG_ERROR
,
779 "Unable to encrypt connection from %s - %s (%d)",
780 con
->http
.hostname
, cssmErrorString(error
), (int)error
);
782 con
->http
.error
= error
;
783 con
->http
.status
= HTTP_ERROR
;
787 CFRelease(con
->http
.tls
);
788 con
->http
.tls
= NULL
;
791 if (con
->http
.tls_credentials
)
793 CFRelease(con
->http
.tls_credentials
);
794 con
->http
.tls_credentials
= NULL
;
800 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Connection from %s now encrypted.",
803 if (!SSLCopyPeerTrust(con
->http
.tls
, &peerTrust
) && peerTrust
)
805 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Received %d peer certificates.",
806 (int)SecTrustGetCertificateCount(peerTrust
));
807 CFRelease(peerTrust
);
810 cupsdLogMessage(CUPSD_LOG_DEBUG
, "Received NO peer certificates.");
817 * 'copy_cdsa_certificate()' - Copy a SSL/TLS certificate from the System
821 static CFArrayRef
/* O - Array of certificates */
822 copy_cdsa_certificate(
823 cupsd_client_t
*con
) /* I - Client connection */
825 OSStatus err
; /* Error info */
826 SecKeychainRef keychain
= NULL
;/* Keychain reference */
827 SecIdentitySearchRef search
= NULL
; /* Search reference */
828 SecIdentityRef identity
= NULL
;/* Identity */
829 CFArrayRef certificates
= NULL
;
830 /* Certificate array */
831 SecPolicyRef policy
= NULL
; /* Policy ref */
832 CFStringRef servername
= NULL
;
834 CFMutableDictionaryRef query
= NULL
; /* Query qualifiers */
835 CFArrayRef list
= NULL
; /* Keychain list */
836 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
837 char localname
[1024];/* Local hostname */
838 # endif /* HAVE_DNSSD || HAVE_AVAHI */
841 cupsdLogMessage(CUPSD_LOG_DEBUG
,
842 "copy_cdsa_certificate: Looking for certs for \"%s\".",
845 if ((err
= SecKeychainOpen(ServerCertificate
, &keychain
)))
847 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot open keychain \"%s\" - %s (%d)",
848 ServerCertificate
, cssmErrorString(err
), (int)err
);
852 servername
= CFStringCreateWithCString(kCFAllocatorDefault
, con
->servername
,
853 kCFStringEncodingUTF8
);
855 policy
= SecPolicyCreateSSL(1, servername
);
858 CFRelease(servername
);
862 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create ssl policy reference");
866 if (!(query
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
867 &kCFTypeDictionaryKeyCallBacks
,
868 &kCFTypeDictionaryValueCallBacks
)))
870 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create query dictionary");
874 list
= CFArrayCreate(kCFAllocatorDefault
, (const void **)&keychain
, 1,
875 &kCFTypeArrayCallBacks
);
877 CFDictionaryAddValue(query
, kSecClass
, kSecClassIdentity
);
878 CFDictionaryAddValue(query
, kSecMatchPolicy
, policy
);
879 CFDictionaryAddValue(query
, kSecReturnRef
, kCFBooleanTrue
);
880 CFDictionaryAddValue(query
, kSecMatchLimit
, kSecMatchLimitOne
);
881 CFDictionaryAddValue(query
, kSecMatchSearchList
, list
);
885 err
= SecItemCopyMatching(query
, (CFTypeRef
*)&identity
);
887 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
888 if (err
&& DNSSDHostName
)
891 * Search for the connection server name failed; try the DNS-SD .local
892 * hostname instead...
895 snprintf(localname
, sizeof(localname
), "%s.local", DNSSDHostName
);
897 cupsdLogMessage(CUPSD_LOG_DEBUG
,
898 "copy_cdsa_certificate: Looking for certs for \"%s\".",
901 servername
= CFStringCreateWithCString(kCFAllocatorDefault
, localname
,
902 kCFStringEncodingUTF8
);
906 policy
= SecPolicyCreateSSL(1, servername
);
909 CFRelease(servername
);
913 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create ssl policy reference");
917 CFDictionarySetValue(query
, kSecMatchPolicy
, policy
);
919 err
= SecItemCopyMatching(query
, (CFTypeRef
*)&identity
);
921 # endif /* HAVE_DNSSD || HAVE_AVAHI */
925 cupsdLogMessage(CUPSD_LOG_DEBUG
,
926 "Cannot find signing key in keychain \"%s\": %s (%d)",
927 ServerCertificate
, cssmErrorString(err
), (int)err
);
931 if (CFGetTypeID(identity
) != SecIdentityGetTypeID())
933 cupsdLogMessage(CUPSD_LOG_ERROR
, "SecIdentity CFTypeID failure.");
937 if ((certificates
= CFArrayCreate(NULL
, (const void **)&identity
,
938 1, &kCFTypeArrayCallBacks
)) == NULL
)
940 cupsdLogMessage(CUPSD_LOG_ERROR
, "Cannot create certificate array");
958 return (certificates
);
963 * 'make_certificate()' - Make a self-signed SSL/TLS certificate.
966 static int /* O - 1 on success, 0 on failure */
967 make_certificate(cupsd_client_t
*con
) /* I - Client connection */
969 # ifdef HAVE_SECGENERATESELFSIGNEDCERTIFICATE
970 int status
= 0; /* Return status */
971 OSStatus err
; /* Error code (if any) */
972 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
973 char localname
[1024];/* Local hostname */
974 # endif /* HAVE_DNSSD || HAVE_AVAHI */
975 const char *servername
; /* Name of server in cert */
976 CFStringRef cfservername
= NULL
;
977 /* CF string for server name */
978 SecIdentityRef ident
= NULL
; /* Identity */
979 SecKeyRef publicKey
= NULL
,
983 CFMutableDictionaryRef keyParams
= NULL
;
984 /* Key generation parameters */
987 cupsdLogMessage(CUPSD_LOG_INFO
,
988 "Generating SSL server key and certificate.");
990 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
991 if (con
->servername
&& isdigit(con
->servername
[0] & 255) && DNSSDHostName
)
993 snprintf(localname
, sizeof(localname
), "%s.local", DNSSDHostName
);
994 servername
= localname
;
997 # endif /* HAVE_DNSSD || HAVE_AVAHI */
998 servername
= con
->servername
;
1000 cfservername
= CFStringCreateWithCString(kCFAllocatorDefault
, servername
,
1001 kCFStringEncodingUTF8
);
1006 * Create a public/private key pair...
1009 keyParams
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
1010 &kCFTypeDictionaryKeyCallBacks
,
1011 &kCFTypeDictionaryValueCallBacks
);
1015 CFDictionaryAddValue(keyParams
, kSecAttrKeyType
, kSecAttrKeyTypeRSA
);
1016 CFDictionaryAddValue(keyParams
, kSecAttrKeySizeInBits
, CFSTR("2048"));
1017 CFDictionaryAddValue(keyParams
, kSecAttrLabel
,
1018 CFSTR("CUPS Self-Signed Certificate"));
1020 err
= SecKeyGeneratePair(keyParams
, &publicKey
, &privateKey
);
1023 cupsdLogMessage(CUPSD_LOG_DEBUG
, "SecKeyGeneratePair returned %ld.",
1029 * Create a self-signed certificate using the public/private key pair...
1032 CFIndex usageInt
= kSecKeyUsageAll
;
1033 CFNumberRef usage
= CFNumberCreate(alloc
, kCFNumberCFIndexType
, &usageInt
);
1034 CFDictionaryRef certParams
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
1035 kSecCSRBasicContraintsPathLen
, CFINT(0),
1036 kSecSubjectAltName
, cfservername
,
1037 kSecCertificateKeyUsage
, usage
,
1041 const void *ca_o
[] = { kSecOidOrganization
, CFSTR("") };
1042 const void *ca_cn
[] = { kSecOidCommonName
, cfservername
};
1043 CFArrayRef ca_o_dn
= CFArrayCreate(kCFAllocatorDefault
, ca_o
, 2, NULL
);
1044 CFArrayRef ca_cn_dn
= CFArrayCreate(kCFAllocatorDefault
, ca_cn
, 2, NULL
);
1045 const void *ca_dn_array
[2];
1047 ca_dn_array
[0] = CFArrayCreate(kCFAllocatorDefault
, (const void **)&ca_o_dn
,
1049 ca_dn_array
[1] = CFArrayCreate(kCFAllocatorDefault
, (const void **)&ca_cn_dn
,
1052 CFArrayRef subject
= CFArrayCreate(kCFAllocatorDefault
, ca_dn_array
, 2,
1054 SecCertificateRef cert
= SecGenerateSelfSignedCertificate(subject
, certParams
,
1058 CFRelease(certParams
);
1062 cupsdLogMessage(CUPSD_LOG_DEBUG
, "SecGenerateSelfSignedCertificate failed.");
1066 ident
= SecIdentityCreate(kCFAllocatorDefault
, cert
, privateKey
);
1069 cupsdLogMessage(CUPSD_LOG_INFO
,
1070 "Created SSL server certificate file \"%s\".",
1074 * Cleanup and return...
1080 CFRelease(cfservername
);
1083 CFRelease(keyParams
);
1092 CFRelease(publicKey
);
1095 CFRelease(publicKey
);
1098 cupsdLogMessage(CUPSD_LOG_ERROR
,
1099 "Unable to create SSL server key and certificate.");
1103 # else /* !HAVE_SECGENERATESELFSIGNEDCERTIFICATE */
1104 int pid
, /* Process ID of command */
1105 status
; /* Status of command */
1106 char command
[1024], /* Command */
1107 *argv
[4], /* Command-line arguments */
1108 *envp
[MAX_ENV
+ 1], /* Environment variables */
1109 keychain
[1024], /* Keychain argument */
1110 infofile
[1024], /* Type-in information for cert */
1111 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1112 localname
[1024], /* Local hostname */
1113 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1114 *servername
; /* Name of server in cert */
1115 cups_file_t
*fp
; /* Seed/info file */
1116 int infofd
; /* Info file descriptor */
1119 # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
1120 if (con
->servername
&& isdigit(con
->servername
[0] & 255) && DNSSDHostName
)
1122 snprintf(localname
, sizeof(localname
), "%s.local", DNSSDHostName
);
1123 servername
= localname
;
1126 # endif /* HAVE_DNSSD || HAVE_AVAHI */
1127 servername
= con
->servername
;
1130 * Run the "certtool" command to generate a self-signed certificate...
1133 if (!cupsFileFind("certtool", getenv("PATH"), 1, command
, sizeof(command
)))
1135 cupsdLogMessage(CUPSD_LOG_ERROR
,
1136 "No SSL certificate and certtool command not found.");
1141 * Create a file with the certificate information fields...
1143 * Note: This assumes that the default questions are asked by the certtool
1147 if ((fp
= cupsTempFile2(infofile
, sizeof(infofile
))) == NULL
)
1149 cupsdLogMessage(CUPSD_LOG_ERROR
,
1150 "Unable to create certificate information file %s - %s",
1151 infofile
, strerror(errno
));
1156 "%s\n" /* Enter key and certificate label */
1157 "r\n" /* Generate RSA key pair */
1158 "2048\n" /* Key size in bits */
1159 "y\n" /* OK (y = yes) */
1160 "b\n" /* Usage (b=signing/encryption) */
1161 "s\n" /* Sign with SHA1 */
1162 "y\n" /* OK (y = yes) */
1163 "%s\n" /* Common name */
1164 "\n" /* Country (default) */
1165 "\n" /* Organization (default) */
1166 "\n" /* Organizational unit (default) */
1167 "\n" /* State/Province (default) */
1168 "%s\n" /* Email address */
1169 "y\n", /* OK (y = yes) */
1170 servername
, servername
, ServerAdmin
);
1173 cupsdLogMessage(CUPSD_LOG_INFO
,
1174 "Generating SSL server key and certificate.");
1176 snprintf(keychain
, sizeof(keychain
), "k=%s", ServerCertificate
);
1178 argv
[0] = "certtool";
1183 cupsdLoadEnv(envp
, MAX_ENV
);
1185 infofd
= open(infofile
, O_RDONLY
);
1187 if (!cupsdStartProcess(command
, argv
, envp
, infofd
, -1, -1, -1, -1, 1, NULL
,
1198 while (waitpid(pid
, &status
, 0) < 0)
1205 cupsdFinishProcess(pid
, command
, sizeof(command
), NULL
);
1209 if (WIFEXITED(status
))
1210 cupsdLogMessage(CUPSD_LOG_ERROR
,
1211 "Unable to create SSL server key and certificate - "
1212 "the certtool command stopped with status %d.",
1213 WEXITSTATUS(status
));
1215 cupsdLogMessage(CUPSD_LOG_ERROR
,
1216 "Unable to create SSL server key and certificate - "
1217 "the certtool command crashed on signal %d.",
1222 cupsdLogMessage(CUPSD_LOG_INFO
,
1223 "Created SSL server certificate file \"%s\".",
1228 # endif /* HAVE_SECGENERATESELFSIGNEDCERTIFICATE */