<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15217] CalendarServer/trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15217">15217</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-10-23 12:37:48 -0700 (Fri, 23 Oct 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Support for pySecureTransport in addition to pyOpenSSL.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkbin_buildsh">CalendarServer/trunk/bin/_build.sh</a></li>
<li><a href="#CalendarServertrunkcalendarserverpushapplepushpy">CalendarServer/trunk/calendarserver/push/applepush.py</a></li>
<li><a href="#CalendarServertrunkcalendarserverpushutilpy">CalendarServer/trunk/calendarserver/push/util.py</a></li>
<li><a href="#CalendarServertrunkcalendarservertapcaldavpy">CalendarServer/trunk/calendarserver/tap/caldav.py</a></li>
<li><a href="#CalendarServertrunkcalendarservertaputilpy">CalendarServer/trunk/calendarserver/tap/util.py</a></li>
<li><a href="#CalendarServertrunkconfcaldavdappleplist">CalendarServer/trunk/conf/caldavd-apple.plist</a></li>
<li><a href="#CalendarServertrunkconfcaldavdtestplist">CalendarServer/trunk/conf/caldavd-test.plist</a></li>
<li><a href="#CalendarServertrunkconflocalserverstestxml">CalendarServer/trunk/conf/localservers-test.xml</a></li>
<li><a href="#CalendarServertrunkrequirementsdevtxt">CalendarServer/trunk/requirements-dev.txt</a></li>
<li><a href="#CalendarServertrunksetuppy">CalendarServer/trunk/setup.py</a></li>
<li><a href="#CalendarServertrunksupport_cache_deps">CalendarServer/trunk/support/_cache_deps</a></li>
<li><a href="#CalendarServertrunktwistedcaldavclientpoolpy">CalendarServer/trunk/twistedcaldav/client/pool.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavstdconfigpy">CalendarServer/trunk/twistedcaldav/stdconfig.py</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>CalendarServer/trunk/lib-patches/Twisted/</li>
<li><a href="#CalendarServertrunklibpatchesTwistedsecuretransportpatch">CalendarServer/trunk/lib-patches/Twisted/securetransport.patch</a></li>
<li><a href="#CalendarServertrunkrequirementscstxt">CalendarServer/trunk/requirements-cs.txt</a></li>
<li><a href="#CalendarServertrunkrequirementsdefaulttxt">CalendarServer/trunk/requirements-default.txt</a></li>
<li><a href="#CalendarServertrunkrequirementsosxtxt">CalendarServer/trunk/requirements-osx.txt</a></li>
<li><a href="#CalendarServertrunkrequirementstwisteddefaulttxt">CalendarServer/trunk/requirements-twisted-default.txt</a></li>
<li><a href="#CalendarServertrunkrequirementstwistedosxtxt">CalendarServer/trunk/requirements-twisted-osx.txt</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#CalendarServertrunkrequirementsstabletxt">CalendarServer/trunk/requirements-stable.txt</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkbin_buildsh"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/bin/_build.sh (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/bin/_build.sh        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/bin/_build.sh        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -92,7 +92,6 @@
</span><span class="cx">   conditional_set do_get &quot;true&quot;;
</span><span class="cx">   conditional_set do_setup &quot;true&quot;;
</span><span class="cx">   conditional_set force_setup &quot;false&quot;;
</span><del>-  conditional_set requirements &quot;${wd}/requirements-dev.txt&quot;
</del><span class="cx">   conditional_set virtualenv_opts &quot;&quot;;
</span><span class="cx"> 
</span><span class="cx">       dev_home=&quot;${wd}/.develop&quot;;
</span><span class="lines">@@ -159,6 +158,19 @@
</span><span class="cx">   else
</span><span class="cx">     hash () { echo &quot;INTERNAL ERROR: No hash function.&quot;; exit 1; }
</span><span class="cx">   fi;
</span><ins>+
+  default_requirements=&quot;${wd}/requirements-default.txt&quot;;
+  use_openssl=&quot;true&quot;
+  if [ -z &quot;${USE_OPENSSL-}&quot; ]; then
+    case &quot;$(uname -s)&quot; in
+      Darwin)
+        default_requirements=&quot;${wd}/requirements-osx.txt&quot;;
+            use_openssl=&quot;false&quot;
+        ;;
+    esac;
+  fi;  
+  conditional_set requirements &quot;${default_requirements}&quot;
+  
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -475,27 +487,29 @@
</span><span class="cx"> 
</span><span class="cx">   # The OpenSSL version number is special. Our strategy is to get the integer
</span><span class="cx">   # value of OPENSSL_VERSION_NUBMER for use in inequality comparison.
</span><del>-  ruler;
</del><ins>+  if [ ${use_openssl} == &quot;true&quot; ]; then
+    ruler;
</ins><span class="cx"> 
</span><del>-  local min_ssl_version=&quot;9470463&quot;;  # OpenSSL 0.9.8zf
</del><ins>+    local min_ssl_version=&quot;9470463&quot;;  # OpenSSL 0.9.8zf
</ins><span class="cx"> 
</span><del>-  local ssl_version=&quot;$(c_macro openssl/ssl.h OPENSSL_VERSION_NUMBER)&quot;;
-  if [ -z &quot;${ssl_version}&quot; ]; then ssl_version=&quot;0x0&quot;; fi;
-  ssl_version=&quot;$(&quot;${bootstrap_python}&quot; -c &quot;print ${ssl_version}&quot;)&quot;;
</del><ins>+    local ssl_version=&quot;$(c_macro openssl/ssl.h OPENSSL_VERSION_NUMBER)&quot;;
+    if [ -z &quot;${ssl_version}&quot; ]; then ssl_version=&quot;0x0&quot;; fi;
+    ssl_version=&quot;$(&quot;${bootstrap_python}&quot; -c &quot;print ${ssl_version}&quot;)&quot;;
</ins><span class="cx"> 
</span><del>-  if [ &quot;${ssl_version}&quot; -ge &quot;${min_ssl_version}&quot; ]; then
-    using_system &quot;OpenSSL&quot;;
-  else
-    local v=&quot;0.9.8zf&quot;;
-    local n=&quot;openssl&quot;;
-    local p=&quot;${n}-${v}&quot;;
</del><ins>+    if [ &quot;${ssl_version}&quot; -ge &quot;${min_ssl_version}&quot; ]; then
+      using_system &quot;OpenSSL&quot;;
+    else
+      local v=&quot;0.9.8zf&quot;;
+      local n=&quot;openssl&quot;;
+      local p=&quot;${n}-${v}&quot;;
</ins><span class="cx"> 
</span><del>-    # use 'config' instead of 'configure'; 'make' instead of 'jmake'.
-    # also pass 'shared' to config to build shared libs.
-    c_dependency -c &quot;config&quot; -m &quot;c69a4a679233f7df189e1ad6659511ec&quot; \
-      -p &quot;make depend&quot; -b &quot;make&quot; \
-      &quot;openssl&quot; &quot;${p}&quot; \
-      &quot;http://www.openssl.org/source/${p}.tar.gz&quot; &quot;shared&quot;;
</del><ins>+      # use 'config' instead of 'configure'; 'make' instead of 'jmake'.
+      # also pass 'shared' to config to build shared libs.
+      c_dependency -c &quot;config&quot; -m &quot;c69a4a679233f7df189e1ad6659511ec&quot; \
+        -p &quot;make depend&quot; -b &quot;make&quot; \
+        &quot;openssl&quot; &quot;${p}&quot; \
+        &quot;http://www.openssl.org/source/${p}.tar.gz&quot; &quot;shared&quot;;
+    fi;
</ins><span class="cx">   fi;
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -689,7 +703,14 @@
</span><span class="cx">     fi;
</span><span class="cx">   done;
</span><span class="cx"> 
</span><ins>+  ruler &quot;Patching Python requirements&quot;;
</ins><span class="cx">   echo &quot;&quot;;
</span><ins>+  if [ ! -e &quot;${dev_patches}/Twisted&quot; ]; then
+          apply_patches &quot;Twisted&quot; &quot;${py_virtualenv}/lib/python2.7/site-packages&quot;
+          touch &quot;${dev_patches}/Twisted&quot;;
+  fi;
+
+  echo &quot;&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunkcalendarserverpushapplepushpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/push/applepush.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/push/applepush.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/calendarserver/push/applepush.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -124,6 +124,7 @@
</span><span class="cx">                     settings[protocol][&quot;PrivateKeyPath&quot;],
</span><span class="cx">                     chainPath=settings[protocol][&quot;AuthorityChainPath&quot;],
</span><span class="cx">                     passphrase=settings[protocol][&quot;Passphrase&quot;],
</span><ins>+                    keychainIdentity=settings[protocol][&quot;KeychainIdentity&quot;],
</ins><span class="cx">                     staggerNotifications=settings[&quot;EnableStaggering&quot;],
</span><span class="cx">                     staggerSeconds=settings[&quot;StaggerSeconds&quot;],
</span><span class="cx">                     testConnector=providerTestConnector,
</span><span class="lines">@@ -144,6 +145,7 @@
</span><span class="cx">                     settings[protocol][&quot;PrivateKeyPath&quot;],
</span><span class="cx">                     chainPath=settings[protocol][&quot;AuthorityChainPath&quot;],
</span><span class="cx">                     passphrase=settings[protocol][&quot;Passphrase&quot;],
</span><ins>+                    keychainIdentity=settings[protocol][&quot;KeychainIdentity&quot;],
</ins><span class="cx">                     testConnector=feedbackTestConnector,
</span><span class="cx">                     reactor=reactor,
</span><span class="cx">                 )
</span><span class="lines">@@ -511,7 +513,7 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(
</span><span class="cx">         self, host, port, certPath, keyPath, chainPath=&quot;&quot;,
</span><del>-        passphrase=&quot;&quot;, sslMethod=&quot;TLSv1_METHOD&quot;, testConnector=None,
</del><ins>+        passphrase=&quot;&quot;, keychainIdentity=&quot;&quot;, sslMethod=&quot;TLSv1_METHOD&quot;, testConnector=None,
</ins><span class="cx">         reactor=None
</span><span class="cx">     ):
</span><span class="cx"> 
</span><span class="lines">@@ -521,6 +523,7 @@
</span><span class="cx">         self.keyPath = keyPath
</span><span class="cx">         self.chainPath = chainPath
</span><span class="cx">         self.passphrase = passphrase
</span><ins>+        self.keychainIdentity = keychainIdentity
</ins><span class="cx">         self.sslMethod = sslMethod
</span><span class="cx">         self.testConnector = testConnector
</span><span class="cx"> 
</span><span class="lines">@@ -543,6 +546,7 @@
</span><span class="cx">                 self.certPath,
</span><span class="cx">                 certificateChainFile=self.chainPath,
</span><span class="cx">                 passwdCallback=passwdCallback,
</span><ins>+                keychainIdentity=self.keychainIdentity,
</ins><span class="cx">                 sslmethod=getattr(OpenSSL.SSL, self.sslMethod)
</span><span class="cx">             )
</span><span class="cx">             connect(GAIEndpoint(self.reactor, self.host, self.port, context),
</span><span class="lines">@@ -554,14 +558,15 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(
</span><span class="cx">         self, store, host, port, certPath, keyPath, chainPath=&quot;&quot;,
</span><del>-        passphrase=&quot;&quot;, sslMethod=&quot;TLSv1_METHOD&quot;,
</del><ins>+        passphrase=&quot;&quot;, keychainIdentity=&quot;&quot;, sslMethod=&quot;TLSv1_METHOD&quot;,
</ins><span class="cx">         staggerNotifications=False, staggerSeconds=3,
</span><span class="cx">         testConnector=None, reactor=None
</span><span class="cx">     ):
</span><span class="cx"> 
</span><span class="cx">         APNConnectionService.__init__(
</span><span class="cx">             self, host, port, certPath, keyPath,
</span><del>-            chainPath=chainPath, passphrase=passphrase, sslMethod=sslMethod,
</del><ins>+            chainPath=chainPath, passphrase=passphrase,
+            keychainIdentity=keychainIdentity, sslMethod=sslMethod,
</ins><span class="cx">             testConnector=testConnector, reactor=reactor)
</span><span class="cx"> 
</span><span class="cx">         self.store = store
</span><span class="lines">@@ -775,13 +780,15 @@
</span><span class="cx"> 
</span><span class="cx">     def __init__(
</span><span class="cx">         self, store, updateSeconds, host, port,
</span><del>-        certPath, keyPath, chainPath=&quot;&quot;, passphrase=&quot;&quot;, sslMethod=&quot;TLSv1_METHOD&quot;,
</del><ins>+        certPath, keyPath, chainPath=&quot;&quot;,
+        passphrase=&quot;&quot;, keychainIdentity=&quot;&quot;, sslMethod=&quot;TLSv1_METHOD&quot;,
</ins><span class="cx">         testConnector=None, reactor=None
</span><span class="cx">     ):
</span><span class="cx"> 
</span><span class="cx">         APNConnectionService.__init__(
</span><span class="cx">             self, host, port, certPath, keyPath,
</span><del>-            chainPath=chainPath, passphrase=passphrase, sslMethod=sslMethod,
</del><ins>+            chainPath=chainPath, passphrase=passphrase,
+            keychainIdentity=keychainIdentity, sslMethod=sslMethod,
</ins><span class="cx">             testConnector=testConnector, reactor=reactor)
</span><span class="cx"> 
</span><span class="cx">         self.store = store
</span></span></pre></div>
<a id="CalendarServertrunkcalendarserverpushutilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/push/util.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/push/util.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/calendarserver/push/util.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -41,7 +41,34 @@
</span><span class="cx">     @return: C{str} topic, or empty string if value is not found
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     certData = open(certPath).read()
</span><del>-    x509 = crypto.load_certificate(crypto.FILETYPE_PEM, certData)
</del><ins>+    return getAPNTopicFromX509(crypto.load_certificate(crypto.FILETYPE_PEM, certData))
+
+
+
+def getAPNTopicFromIdentity(identity):
+    &quot;&quot;&quot;
+    Given a keychain identity certificate, extract the UID value portion of the
+    subject, which in this context is used for the associated APN topic.
+
+    @param identity: keychain identity to lookup
+    @type identity: C{str}
+
+    @return: C{str} topic, or empty string if value is not found
+    &quot;&quot;&quot;
+    return getAPNTopicFromX509(crypto.load_certificate(None, identity))
+
+
+
+def getAPNTopicFromX509(x509):
+    &quot;&quot;&quot;
+    Given an L{X509} certificate, extract the UID value portion of the
+    subject, which in this context is used for the associated APN topic.
+
+    @param x509: the certificate
+    @type x509: L{X509}
+
+    @return: C{str} topic, or empty string if value is not found
+    &quot;&quot;&quot;
</ins><span class="cx">     subject = x509.get_subject()
</span><span class="cx">     components = subject.get_components()
</span><span class="cx">     for name, value in components:
</span></span></pre></div>
<a id="CalendarServertrunkcalendarservertapcaldavpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/tap/caldav.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/tap/caldav.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -835,6 +835,7 @@
</span><span class="cx">             config.SSLCertificate,
</span><span class="cx">             certificateChainFile=config.SSLAuthorityChain,
</span><span class="cx">             passwdCallback=getSSLPassphrase,
</span><ins>+            keychainIdentity=config.SSLKeychainIdentity,
</ins><span class="cx">             sslmethod=getattr(OpenSSL.SSL, config.SSLMethod),
</span><span class="cx">             ciphers=config.SSLCiphers.strip(),
</span><span class="cx">             verifyClient=config.Authentication.ClientCertificate.Enabled,
</span></span></pre></div>
<a id="CalendarServertrunkcalendarservertaputilpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/tap/util.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/tap/util.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/calendarserver/tap/util.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> from calendarserver.provision.root import RootResource
</span><span class="cx"> from calendarserver.push.applepush import APNSubscriptionResource
</span><span class="cx"> from calendarserver.push.notifier import NotifierFactory
</span><del>-from calendarserver.push.util import getAPNTopicFromCertificate
</del><ins>+from calendarserver.push.util import getAPNTopicFromCertificate, getAPNTopicFromIdentity
</ins><span class="cx"> from calendarserver.tools import diagnose
</span><span class="cx"> from calendarserver.tools.util import checkDirectory
</span><span class="cx"> from calendarserver.webadmin.landing import WebAdminLandingResource
</span><span class="lines">@@ -1301,7 +1301,18 @@
</span><span class="cx">     and that it's valid.
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-    if config.SSLCertificate:
</del><ins>+    if hasattr(OpenSSL, &quot;__SecureTransport__&quot;):
+        if config.SSLKeychainIdentity:
+            # Fall through to see if we can load the identity from the keychain
+            certificate_title = &quot;Keychain: {}&quot;.format(config.SSLKeychainIdentity)
+        else:
+            message = (
+                &quot;No Keychain Identity was set for TLS&quot;
+            )
+            postAlert(&quot;MissingKeychainIdentityAlert&quot;, [])
+            return False, message
+
+    elif config.SSLCertificate:
</ins><span class="cx">         if not os.path.exists(config.SSLCertificate):
</span><span class="cx">             message = (
</span><span class="cx">                 &quot;The configured TLS certificate ({cert}) is missing&quot;.format(
</span><span class="lines">@@ -1310,34 +1321,44 @@
</span><span class="cx">             )
</span><span class="cx">             postAlert(&quot;MissingCertificateAlert&quot;, [&quot;path&quot;, config.SSLCertificate])
</span><span class="cx">             return False, message
</span><ins>+
+        length = os.stat(config.SSLCertificate).st_size
+        if length == 0:
+                message = (
+                    &quot;The configured TLS certificate ({cert}) is empty&quot;.format(
+                        cert=config.SSLCertificate
+                    )
+                )
+                return False, message
+        certificate_title = config.SSLCertificate
</ins><span class="cx">     else:
</span><span class="cx">         return True, &quot;TLS disabled&quot;
</span><span class="cx"> 
</span><del>-    length = os.stat(config.SSLCertificate).st_size
-    if length == 0:
-            message = (
-                &quot;The configured TLS certificate ({cert}) is empty&quot;.format(
-                    cert=config.SSLCertificate
-                )
-            )
-            return False, message
-
</del><span class="cx">     try:
</span><span class="cx">         ChainingOpenSSLContextFactory(
</span><span class="cx">             config.SSLPrivateKey,
</span><span class="cx">             config.SSLCertificate,
</span><span class="cx">             certificateChainFile=config.SSLAuthorityChain,
</span><span class="cx">             passwdCallback=getSSLPassphrase,
</span><ins>+            keychainIdentity=config.SSLKeychainIdentity,
</ins><span class="cx">             sslmethod=getattr(OpenSSL.SSL, config.SSLMethod),
</span><span class="cx">             ciphers=config.SSLCiphers.strip()
</span><span class="cx">         )
</span><span class="cx">     except Exception as e:
</span><del>-        message = (
-            &quot;The configured TLS certificate ({cert}) cannot be used: {reason}&quot;.format(
-                cert=config.SSLCertificate,
-                reason=str(e)
</del><ins>+        if hasattr(OpenSSL, &quot;__SecureTransport__&quot;):
+            message = (
+                &quot;The configured TLS Keychain Identity ({cert}) cannot be used: {reason}&quot;.format(
+                    cert=certificate_title,
+                    reason=str(e)
+                )
</ins><span class="cx">             )
</span><del>-        )
</del><ins>+        else:
+            message = (
+                &quot;The configured TLS certificate ({cert}) cannot be used: {reason}&quot;.format(
+                    cert=certificate_title,
+                    reason=str(e)
+                )
+            )
</ins><span class="cx">         return False, message
</span><span class="cx"> 
</span><span class="cx">     return True, &quot;TLS enabled&quot;
</span><span class="lines">@@ -1358,39 +1379,62 @@
</span><span class="cx">             protoConfig = config.Notifications.Services.APNS[protocol]
</span><span class="cx"> 
</span><span class="cx">             # Verify the cert exists
</span><del>-            if not os.path.exists(protoConfig.CertificatePath):
-                message = (
-                    &quot;The {proto} APNS certificate ({cert}) is missing&quot;.format(
-                        proto=protocol,
-                        cert=protoConfig.CertificatePath
</del><ins>+            if hasattr(OpenSSL, &quot;__SecureTransport__&quot;):
+                if protoConfig.KeychainIdentity:
+                    # Verify we can extract the topic
+                    if not protoConfig.Topic:
+                        topic = getAPNTopicFromIdentity(protoConfig.KeychainIdentity)
+                        protoConfig.Topic = topic
+                    if not protoConfig.Topic:
+                        postAlert(&quot;PushNotificationKeychainIdentityAlert&quot;, [])
+                        message = &quot;Cannot extract APN topic&quot;
+                        return False, message
+
+                    # Fall through to see if we can load the identity from the keychain
+                    certificate_title = &quot;Keychain: {}&quot;.format(protoConfig.KeychainIdentity)
+                else:
+                    message = (
+                        &quot;No {proto} APNS Keychain Identity was set&quot;.format(
+                            proto=protocol,
+                        )
</ins><span class="cx">                     )
</span><del>-                )
-                postAlert(&quot;PushNotificationCertificateAlert&quot;, [])
-                return False, message
</del><ins>+                    postAlert(&quot;MissingKeychainIdentityAlert&quot;, [])
+                    return False, message
</ins><span class="cx"> 
</span><del>-            # Verify we can extract the topic
-            if not protoConfig.Topic:
-                topic = getAPNTopicFromCertificate(protoConfig.CertificatePath)
-                protoConfig.Topic = topic
-            if not protoConfig.Topic:
-                postAlert(&quot;PushNotificationCertificateAlert&quot;, [])
-                message = &quot;Cannot extract APN topic&quot;
-                return False, message
</del><ins>+            else:
+                if not os.path.exists(protoConfig.CertificatePath):
+                    message = (
+                        &quot;The {proto} APNS certificate ({cert}) is missing&quot;.format(
+                            proto=protocol,
+                            cert=protoConfig.CertificatePath
+                        )
+                    )
+                    postAlert(&quot;PushNotificationCertificateAlert&quot;, [])
+                    return False, message
</ins><span class="cx"> 
</span><del>-            # Verify we can acquire the passphrase
-            if not protoConfig.Passphrase:
-                try:
-                    passphrase = getPasswordFromKeychain(accountName)
-                    protoConfig.Passphrase = passphrase
-                except KeychainAccessError:
-                    # The system doesn't support keychain
-                    pass
-                except KeychainPasswordNotFound:
-                    # The password doesn't exist in the keychain.
</del><ins>+                # Verify we can extract the topic
+                if not protoConfig.Topic:
+                    topic = getAPNTopicFromCertificate(protoConfig.CertificatePath)
+                    protoConfig.Topic = topic
+                if not protoConfig.Topic:
</ins><span class="cx">                     postAlert(&quot;PushNotificationCertificateAlert&quot;, [])
</span><del>-                    message = &quot;Cannot retrieve APN passphrase from keychain&quot;
</del><ins>+                    message = &quot;Cannot extract APN topic&quot;
</ins><span class="cx">                     return False, message
</span><span class="cx"> 
</span><ins>+                # Verify we can acquire the passphrase
+                if not protoConfig.Passphrase:
+                    try:
+                        passphrase = getPasswordFromKeychain(accountName)
+                        protoConfig.Passphrase = passphrase
+                    except KeychainAccessError:
+                        # The system doesn't support keychain
+                        pass
+                    except KeychainPasswordNotFound:
+                        # The password doesn't exist in the keychain.
+                        postAlert(&quot;PushNotificationCertificateAlert&quot;, [])
+                        message = &quot;Cannot retrieve APN passphrase from keychain&quot;
+                        return False, message
+
</ins><span class="cx">             # Let OpenSSL try to use the cert
</span><span class="cx">             try:
</span><span class="cx">                 if protoConfig.Passphrase:
</span><span class="lines">@@ -1403,16 +1447,26 @@
</span><span class="cx">                     protoConfig.CertificatePath,
</span><span class="cx">                     certificateChainFile=protoConfig.AuthorityChainPath,
</span><span class="cx">                     passwdCallback=passwdCallback,
</span><ins>+                    keychainIdentity=protoConfig.KeychainIdentity,
</ins><span class="cx">                     sslmethod=getattr(OpenSSL.SSL, &quot;TLSv1_METHOD&quot;),
</span><span class="cx">                 )
</span><span class="cx">             except Exception as e:
</span><del>-                message = (
-                    &quot;The {proto} APNS certificate ({cert}) cannot be used: {reason}&quot;.format(
-                        proto=protocol,
-                        cert=protoConfig.CertificatePath,
-                        reason=str(e)
</del><ins>+                if hasattr(OpenSSL, &quot;__SecureTransport__&quot;):
+                    message = (
+                        &quot;The {proto} APNS Keychain Identity ({cert}) cannot be used: {reason}&quot;.format(
+                            proto=protocol,
+                            cert=certificate_title,
+                            reason=str(e)
+                        )
</ins><span class="cx">                     )
</span><del>-                )
</del><ins>+                else:
+                    message = (
+                        &quot;The {proto} APNS certificate ({cert}) cannot be used: {reason}&quot;.format(
+                            proto=protocol,
+                            cert=certificate_title,
+                            reason=str(e)
+                        )
+                    )
</ins><span class="cx">                 postAlert(&quot;PushNotificationCertificateAlert&quot;, [])
</span><span class="cx">                 return False, message
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunkconfcaldavdappleplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/caldavd-apple.plist (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/caldavd-apple.plist        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/conf/caldavd-apple.plist        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -353,19 +353,11 @@
</span><span class="cx">         SSL/TLS
</span><span class="cx">       --&gt;
</span><span class="cx"> 
</span><del>-    &lt;!-- Public key --&gt;
-    &lt;key&gt;SSLCertificate&lt;/key&gt;
</del><ins>+    &lt;!-- Keychain identity to use instead of cert files --&gt;
+    &lt;key&gt;SSLKeychainIdentity&lt;/key&gt;
</ins><span class="cx">     &lt;string&gt;&lt;/string&gt;
</span><span class="cx"> 
</span><del>-    &lt;!-- SSL authority chain (for intermediate certs) --&gt;
-    &lt;key&gt;SSLAuthorityChain&lt;/key&gt;
-    &lt;string&gt;&lt;/string&gt;
</del><span class="cx"> 
</span><del>-    &lt;!-- Private key --&gt;
-    &lt;key&gt;SSLPrivateKey&lt;/key&gt;
-    &lt;string&gt;&lt;/string&gt;
-
-
</del><span class="cx">     &lt;!--
</span><span class="cx">         Process management
</span><span class="cx">       --&gt;
</span></span></pre></div>
<a id="CalendarServertrunkconfcaldavdtestplist"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/caldavd-test.plist (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/caldavd-test.plist        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/conf/caldavd-test.plist        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -573,7 +573,11 @@
</span><span class="cx">     &lt;key&gt;SSLPrivateKey&lt;/key&gt;
</span><span class="cx">     &lt;string&gt;twistedcaldav/test/data/server.pem&lt;/string&gt;
</span><span class="cx"> 
</span><ins>+    &lt;!-- Keychain identity to use instead of cert files --&gt;
+    &lt;key&gt;SSLKeychainIdentity&lt;/key&gt;
+    &lt;string&gt;org.calendarserver.test&lt;/string&gt;
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     &lt;!--
</span><span class="cx">         Process management
</span><span class="cx">       --&gt;
</span></span></pre></div>
<a id="CalendarServertrunkconflocalserverstestxml"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/conf/localservers-test.xml (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/conf/localservers-test.xml        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/conf/localservers-test.xml        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx"> &lt;servers&gt;
</span><span class="cx">   &lt;server&gt;
</span><span class="cx">     &lt;id&gt;A&lt;/id&gt;
</span><del>-    &lt;uri&gt;http://localhost:8008&lt;/uri&gt;
</del><ins>+    &lt;uri&gt;https://localhost:8443&lt;/uri&gt;
</ins><span class="cx">     &lt;allowed-from&gt;127.0.0.1&lt;/allowed-from&gt;
</span><span class="cx">     &lt;allowed-from&gt;::1&lt;/allowed-from&gt;
</span><span class="cx">     &lt;allowed-from&gt;::ffff:127.0.0.1&lt;/allowed-from&gt;
</span><span class="lines">@@ -29,7 +29,7 @@
</span><span class="cx">   &lt;/server&gt;
</span><span class="cx">   &lt;server&gt;
</span><span class="cx">     &lt;id&gt;B&lt;/id&gt;
</span><del>-    &lt;uri&gt;http://localhost:8108&lt;/uri&gt;
</del><ins>+    &lt;uri&gt;https://localhost:8543&lt;/uri&gt;
</ins><span class="cx">     &lt;allowed-from&gt;127.0.0.1&lt;/allowed-from&gt;
</span><span class="cx">     &lt;allowed-from&gt;::1&lt;/allowed-from&gt;
</span><span class="cx">     &lt;allowed-from&gt;::ffff:127.0.0.1&lt;/allowed-from&gt;
</span></span></pre></div>
<a id="CalendarServertrunklibpatchesTwistedsecuretransportpatch"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/lib-patches/Twisted/securetransport.patch (0 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/lib-patches/Twisted/securetransport.patch                                (rev 0)
+++ CalendarServer/trunk/lib-patches/Twisted/securetransport.patch        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+Index: twisted/internet/_sslverify.py
+===================================================================
+--- twisted/internet/_sslverify.py        (revision 45115)
++++ twisted/internet/_sslverify.py        (working copy)
+@@ -162,7 +162,9 @@

+     major, minor = list(int(part) for part in lib.__version__.split(&quot;.&quot;))[:2]

+-    if (major, minor) &gt;= (0, 12):
++    if hasattr(lib, &quot;__SecureTransport__&quot;):
++        pass
++    elif (major, minor) &gt;= (0, 12):
+         try:
+             from service_identity import VerificationError
+             from service_identity.pyopenssl import verify_hostname
+
+Index: twisted/protocols/tls.py
+===================================================================
+--- twisted/protocols/tls.py        (revision 45115)
++++ twisted/protocols/tls.py        (working copy)
+@@ -660,7 +660,9 @@
+         @rtype: L{OpenSSL.SSL.Connection}
+         &quot;&quot;&quot;
+         context = self._oldStyleContextFactory.getContext()
+-        return Connection(context, None)
++        connection = Connection(context, None)
++        connection.set_app_data(protocol)
++        return connection


+     def serverConnectionForTLS(self, protocol):
</ins></span></pre></div>
<a id="CalendarServertrunkrequirementscstxt"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/requirements-cs.txt (0 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-cs.txt                                (rev 0)
+++ CalendarServer/trunk/requirements-cs.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -0,0 +1,39 @@
</span><ins>+##
+# Main CalendarServer dependency (does not include Twisted)
+##
+
+--editable .  # calendarserver
+
+    zope.interface==4.1.2
+
+    --editable svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@15216#egg=twextpy
+        #cffi==1.3.0
+        #    pycparser==2.13
+        #twisted
+
+        # [LDAP] extra
+            python-ldap==2.4.19
+                #setuptools
+
+        # [DAL] extra
+              sqlparse==0.1.14  # Compat issue in 0.1.15; fix before updating
+
+        # [OpenDirectory] extra
+            #pyobjc-framework-OpenDirectory  # Use system module
+
+        # [Postgres] extra
+            pg8000==1.10.2
+
+        # [Oracle] extra
+            #cx_Oracle==5.2  # Needs manual patch
+
+    --editable svn+http://svn.calendarserver.org/repository/calendarserver/PyKerberos/trunk@15140#egg=kerberos
+
+    --editable svn+http://svn.calendarserver.org/repository/calendarserver/PyCalendar/trunk@15020#egg=pycalendar
+    python-dateutil==1.5  # Note: v2.0+ is for Python 3
+    pytz==2015.4
+
+    psutil==2.2.1
+    setproctitle==1.1.8
+    # xattr==0.7.5  # Only needed for upgrades from ancient versions.  Added in _cache_deps.
+        #cffi
</ins></span></pre></div>
<a id="CalendarServertrunkrequirementsdefaulttxt"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/requirements-default.txt (0 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-default.txt                                (rev 0)
+++ CalendarServer/trunk/requirements-default.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+##
+# Set of dependencies for non-OS X systems.
+##
+
+--requirement requirements-cs.txt
+--requirement requirements-twisted-default.txt
+--requirement requirements-dev.txt
</ins></span></pre></div>
<a id="CalendarServertrunkrequirementsdevtxt"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/requirements-dev.txt (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-dev.txt        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/requirements-dev.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -1,6 +1,3 @@
</span><del>-# Get master requirements
---requirement requirements-stable.txt
-
</del><span class="cx"> # Additional dependencies for development and testing
</span><span class="cx"> pyflakes
</span><span class="cx"> docutils
</span></span></pre></div>
<a id="CalendarServertrunkrequirementsosxtxt"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/requirements-osx.txt (0 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-osx.txt                                (rev 0)
+++ CalendarServer/trunk/requirements-osx.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+##
+# Set of dependencies for OS X systems.
+##
+
+--requirement requirements-cs.txt
+--requirement requirements-twisted-osx.txt
+--requirement requirements-dev.txt
</ins></span></pre></div>
<a id="CalendarServertrunkrequirementsstabletxt"></a>
<div class="delfile"><h4>Deleted: CalendarServer/trunk/requirements-stable.txt (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-stable.txt        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/requirements-stable.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -1,80 +0,0 @@
</span><del>-##
-#
-# Specify specific versions of our dependencies here.
-#
-##
-#
-# This defines the versions of dependencies that we are developing and
-# testing with.
-#
-# Other versions of dependencies are likely to work in most cases, but
-# here you can see what our automated builds are using, so this
-# combination is known to work.
-#
-##
-#
-# This file should contain every module in the output of:
-#   ./bin/dependencies -a
-#
-##
-
---editable .  # calendarserver
-
-    zope.interface==4.1.2
-
-    Twisted==15.2.1
-        #zope.interface
-
-        # NOTE: Twisted also uses pyOpenSSL, pycrypto and service_identity,
-        #   but doesn't specify them as dependencies, so that are explicitly
-        #   added to calendarserver.
-        #pyOpenSSL
-        service_identity==14.0.0
-            characteristic==14.3.0
-            pyasn1==0.1.7
-            pyasn1-modules==0.0.5
-            #pyOpenSSL
-        pycrypto==2.6.1
-
-    --editable svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@15169#egg=twextpy
-        cffi==1.1.0
-            pycparser==2.13
-        #twisted
-
-        # [LDAP] extra
-            python-ldap==2.4.19
-                #setuptools
-
-        # [DAL] extra
-              sqlparse==0.1.14  # Compat issue in 0.1.15; fix before updating
-
-        # [OpenDirectory] extra
-            #pyobjc-framework-OpenDirectory  # Use system module
-
-        # [Postgres] extra
-            pg8000==1.10.2
-
-        # [Oracle] extra
-            #cx_Oracle==5.2  # Needs manual patch
-
-    pyOpenSSL==0.14
-        cryptography==0.9
-                idna
-            #pyasn1
-            #cffi
-            enum34==1.0.4
-            ipaddress
-            setuptools==17.0
-            #six
-        six==1.9.0
-
-    --editable svn+http://svn.calendarserver.org/repository/calendarserver/PyKerberos/trunk@15140#egg=kerberos
-
-    --editable svn+http://svn.calendarserver.org/repository/calendarserver/PyCalendar/trunk@15020#egg=pycalendar
-    python-dateutil==1.5  # Note: v2.0+ is for Python 3
-    pytz==2015.4
-
-    psutil==2.2.1
-    setproctitle==1.1.8
-    # xattr==0.7.5  # Only needed for upgrades from ancient versions.  Added in _cache_deps.
-        #cffi
</del></span></pre></div>
<a id="CalendarServertrunkrequirementstwisteddefaulttxt"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/requirements-twisted-default.txt (0 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-twisted-default.txt                                (rev 0)
+++ CalendarServer/trunk/requirements-twisted-default.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+##
+# Twisted dependency for non-OS X systems (uses pyOpenSSL).
+##
+
+
+Twisted==15.2.1
+    #zope.interface
+
+    # NOTE: Twisted also uses pyOpenSSL, pycrypto and service_identity,
+    #   but doesn't specify them as dependencies, so that are explicitly
+    #   added to calendarserver.
+    #pyOpenSSL
+    service_identity==14.0.0
+        characteristic==14.3.0
+        pyasn1==0.1.7
+        pyasn1-modules==0.0.5
+        #pyOpenSSL
+    pycrypto==2.6.1
+
+    pyOpenSSL==0.14
+        cryptography==0.9
+                idna
+            #pyasn1
+            #cffi
+            enum34==1.0.4
+            ipaddress
+            setuptools==17.0
+            #six
+        six==1.9.0
</ins></span></pre></div>
<a id="CalendarServertrunkrequirementstwistedosxtxt"></a>
<div class="addfile"><h4>Added: CalendarServer/trunk/requirements-twisted-osx.txt (0 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/requirements-twisted-osx.txt                                (rev 0)
+++ CalendarServer/trunk/requirements-twisted-osx.txt        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+##
+# Twisted dependency for OS X systems (uses pySecureTransport).
+##
+
+Twisted==15.2.1
+    #zope.interface
+    pycrypto==2.6.1
+
+    --editable svn+http://svn.calendarserver.org/repository/calendarserver/OSXFrameworks/trunk@15215#egg=osxframeworks
+        cffi==1.3.0
+            pycparser==2.13
+
+    --editable svn+http://svn.calendarserver.org/repository/calendarserver/PySecureTransport/trunk@15213#egg=pysecuretransport
+
</ins></span></pre></div>
<a id="CalendarServertrunksetuppy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/setup.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/setup.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/setup.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -18,13 +18,13 @@
</span><span class="cx"> 
</span><span class="cx"> from __future__ import print_function
</span><span class="cx"> 
</span><del>-import os
</del><span class="cx"> from os.path import dirname, basename, abspath, join as joinpath, normpath
</span><del>-import subprocess
-
-import errno
</del><span class="cx"> from setuptools import setup, find_packages as setuptools_find_packages
</span><span class="cx"> from xml.etree import ElementTree
</span><ins>+import errno
+import os
+import subprocess
+import sys
</ins><span class="cx"> 
</span><span class="cx"> base_version = &quot;8.0&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -326,8 +326,6 @@
</span><span class="cx">     &quot;twextpy&quot;,
</span><span class="cx"> 
</span><span class="cx">     # Security frameworks
</span><del>-    &quot;pyOpenSSL&gt;=0.14&quot;,    # also for Twisted
-    &quot;service_identity&quot;,   # for Twisted
</del><span class="cx">     &quot;pycrypto&quot;,           # for Twisted
</span><span class="cx">     &quot;kerberos&quot;,
</span><span class="cx"> 
</span><span class="lines">@@ -346,6 +344,17 @@
</span><span class="cx">     &quot;setproctitle&quot;,
</span><span class="cx"> ]
</span><span class="cx"> 
</span><ins>+if sys.platform == &quot;darwin&quot;:
+    install_requirements.extend([
+        &quot;OSXFrameworks&quot;,
+        &quot;pySecureTransport&quot;,
+    ])
+else:
+    install_requirements.extend([
+        &quot;pyOpenSSL&gt;=0.14&quot;,    # also for Twisted
+        &quot;service_identity&quot;,   # for Twisted
+    ])
+
</ins><span class="cx"> extras_requirements = {
</span><span class="cx">     &quot;LDAP&quot;: [&quot;twextpy[LDAP]&quot;],
</span><span class="cx">     &quot;OpenDirectory&quot;: [&quot;twextpy[OpenDirectory]&quot;],
</span></span></pre></div>
<a id="CalendarServertrunksupport_cache_deps"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/support/_cache_deps (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/support/_cache_deps        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/support/_cache_deps        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> export PATH=&quot;/Applications/Server.app/Contents/ServerRoot/usr/bin:${PATH}&quot;;
</span><span class="cx"> 
</span><del>-requirements=&quot;${wd}/requirements-stable.txt&quot;;
</del><ins>+requirements=&quot;${wd}/requirements-osx.txt&quot;;
</ins><span class="cx"> extra_features=&quot;OpenDirectory,Postgres&quot;;
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavclientpoolpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/client/pool.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/client/pool.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/twistedcaldav/client/pool.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -424,8 +424,9 @@
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     from twistedcaldav.config import config
</span><span class="cx">     return ChainingOpenSSLContextFactory(
</span><del>-        config.SSLPrivateKey, config.SSLCertificate,
-        certificateChainFile=config.SSLAuthorityChain,
</del><ins>+        &quot;&quot;, &quot;&quot;,
+        certificateChainFile=&quot;&quot;,
+        keychainIdentity=&quot;&quot;,
</ins><span class="cx">         sslmethod=getattr(OpenSSL.SSL, config.SSLMethod)
</span><span class="cx">     )
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavstdconfigpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py (15216 => 15217)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/stdconfig.py        2015-10-23 19:26:11 UTC (rev 15216)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py        2015-10-23 19:37:48 UTC (rev 15217)
</span><span class="lines">@@ -464,11 +464,12 @@
</span><span class="cx">     #
</span><span class="cx">     # SSL/TLS
</span><span class="cx">     #
</span><del>-    &quot;SSLCertificate&quot;     : &quot;&quot;, # Public key
-    &quot;SSLPrivateKey&quot;      : &quot;&quot;, # Private key
-    &quot;SSLAuthorityChain&quot;  : &quot;&quot;, # Certificate Authority Chain
-    &quot;SSLPassPhraseDialog&quot;: &quot;/etc/apache2/getsslpassphrase&quot;,
-    &quot;SSLCertAdmin&quot;       : &quot;/Applications/Server.app/Contents/ServerRoot/usr/sbin/certadmin&quot;,
</del><ins>+    &quot;SSLCertificate&quot;      : &quot;&quot;, # Public key
+    &quot;SSLPrivateKey&quot;       : &quot;&quot;, # Private key
+    &quot;SSLAuthorityChain&quot;   : &quot;&quot;, # Certificate Authority Chain
+    &quot;SSLPassPhraseDialog&quot; : &quot;/etc/apache2/getsslpassphrase&quot;,
+    &quot;SSLCertAdmin&quot;        : &quot;/Applications/Server.app/Contents/ServerRoot/usr/sbin/certadmin&quot;,
+    &quot;SSLKeychainIdentity&quot; : &quot;&quot;, # Keychain identity to use in place of cert files
</ins><span class="cx"> 
</span><span class="cx">     #
</span><span class="cx">     # Process management
</span><span class="lines">@@ -843,6 +844,7 @@
</span><span class="cx">                     &quot;PrivateKeyPath&quot; : &quot;Certificates/apns:com.apple.calendar.key.pem&quot;,
</span><span class="cx">                     &quot;AuthorityChainPath&quot; : &quot;Certificates/apns:com.apple.calendar.chain.pem&quot;,
</span><span class="cx">                     &quot;Passphrase&quot; : &quot;&quot;,
</span><ins>+                    &quot;KeychainIdentity&quot; : &quot;apns:com.apple.calendar&quot;,
</ins><span class="cx">                     &quot;Topic&quot; : &quot;&quot;,
</span><span class="cx">                 },
</span><span class="cx">                 &quot;CardDAV&quot; : {
</span><span class="lines">@@ -850,6 +852,7 @@
</span><span class="cx">                     &quot;PrivateKeyPath&quot; : &quot;Certificates/apns:com.apple.contact.key.pem&quot;,
</span><span class="cx">                     &quot;AuthorityChainPath&quot; : &quot;Certificates/apns:com.apple.contact.chain.pem&quot;,
</span><span class="cx">                     &quot;Passphrase&quot; : &quot;&quot;,
</span><ins>+                    &quot;KeychainIdentity&quot; : &quot;apns:com.apple.contact&quot;,
</ins><span class="cx">                     &quot;Topic&quot; : &quot;&quot;,
</span><span class="cx">                 },
</span><span class="cx">             },
</span><span class="lines">@@ -1731,9 +1734,10 @@
</span><span class="cx">                         service[direction].Username,
</span><span class="cx">                         service[direction].Server
</span><span class="cx">                     )
</span><del>-                    password = getPasswordFromKeychain(account)
-                    service[direction][&quot;Password&quot;] = password
-                    log.info(&quot;iMIP %s password successfully retreived from keychain&quot; % (direction,))
</del><ins>+                    if not service[direction][&quot;Password&quot;]:
+                        password = getPasswordFromKeychain(account)
+                        service[direction][&quot;Password&quot;] = password
+                        log.info(&quot;iMIP %s password successfully retrieved from keychain&quot; % (direction,))
</ins><span class="cx">                 except KeychainAccessError:
</span><span class="cx">                     # The system doesn't support keychain
</span><span class="cx">                     pass
</span></span></pre>
</div>
</div>

</body>
</html>