<!-- 
RSS generated by JIRA (9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66) at Wed Feb 07 21:41:03 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary append 'field=key&field=summary' to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>MongoDB Jira</title>
    <link>https://jira.mongodb.org</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>9.7.1</version>
        <build-number>970001</build-number>
        <build-date>13-04-2023</build-date>
    </build-info>


<item>
            <title>[CSHARP-1914] Certificate Private Keys being dropped</title>
                <link>https://jira.mongodb.org/browse/CSHARP-1914</link>
                <project id="10041" key="CSHARP">C# Driver</project>
                    <description>&lt;p&gt;The use of certificates for authentication appears to be currently broken.&lt;/p&gt;

&lt;p&gt;We recently updated from 2.2.3 to 2.4.1, after which our clients saw connection issues against all clusters using certificates. &lt;/p&gt;

&lt;p&gt;Specifically, on the client side we encountered timeouts of the form:&lt;/p&gt;

&lt;p&gt;{{System.TimeoutException: A timeout occured after 30000ms selecting a server using CompositeServerSelector{ Selectors = ReadPreferenceServerSelector{ ReadPreference = &lt;/p&gt;
{ Mode : Primary }
&lt;p&gt; }, LatencyLimitingServerSelector&lt;/p&gt;
{ AllowedLatencyRange = 00:00:00.0150000 }
&lt;p&gt; }. Client view of cluster state is { ClusterId : &quot;1&quot;, ConnectionMode : &quot;Automatic&quot;, Type : &quot;Unknown&quot;, State : &quot;Disconnected&quot;, Servers : [{ ServerId: &quot;&lt;/p&gt;
{ ClusterId : 1, EndPoint : &quot;Unspecified/wint-dev-vm102:27017&quot; }
&lt;p&gt;&quot;, EndPoint: &quot;Unspecified/wint-dev-vm102:27017&quot;, State: &quot;Disconnected&quot;, Type: &quot;Unknown&quot;, HeartbeatException: &quot;MongoDB.Driver.MongoConnectionException: An exception occurred while opening a connection to the server. ---&amp;gt; System.InvalidOperationException: Invalid BinaryConnection state transition from 2 to Failed.}}&lt;/p&gt;

&lt;p&gt;On the server side:&lt;/p&gt;

&lt;p&gt;{{&lt;span class=&quot;error&quot;&gt;&amp;#91;initandlisten&amp;#93;&lt;/span&gt; connection accepted from 10.105.0.229:53377 #673429 (425 connections now open)&lt;br/&gt;
&lt;span class=&quot;error&quot;&gt;&amp;#91;conn673429&amp;#93;&lt;/span&gt; no SSL certificate provided by peer; connection rejected&lt;br/&gt;
&lt;span class=&quot;error&quot;&gt;&amp;#91;conn673429&amp;#93;&lt;/span&gt; end connection 10.105.0.229:53377 (424 connections now open)}}&lt;/p&gt;

&lt;p&gt;Having looked into it, it appears that since 2.3.0 the private key is dropped on all X509Certificate2 certificates. This occurs in the SslSettings.CloneCertificate method at &lt;a href=&quot;https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/SslSettings.cs#L260&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/SslSettings.cs#L260&lt;/a&gt; and can be replicated using the following program:&lt;/p&gt;

&lt;p&gt;{{using System;&lt;br/&gt;
using System.Security.Cryptography.X509Certificates;&lt;/p&gt;

&lt;p&gt;namespace CertificateTest&lt;br/&gt;
{&lt;br/&gt;
    public class Program&lt;br/&gt;
    {&lt;br/&gt;
        public static void Main(string[] args)&lt;br/&gt;
        {&lt;br/&gt;
            string certificate = @&quot;C:/Certificates/testcert.pfx&quot;;&lt;br/&gt;
            //string certificate = @&quot;C:\Certificates\testcert.pfx&quot;;&lt;br/&gt;
            string passphrase = &quot;password&quot;;&lt;/p&gt;

&lt;p&gt;            var cert = new X509Certificate2(certificate, passphrase, X509KeyStorageFlags.Exportable);&lt;/p&gt;

&lt;p&gt;            Console.WriteLine($&quot;cert.HasPrivateKey: &lt;/p&gt;
{cert.HasPrivateKey}
&lt;p&gt;&quot;);&lt;br/&gt;
            Console.WriteLine();&lt;br/&gt;
            Console.WriteLine($&quot;new X509Certificate2(cert.Export(X509ContentType.Cert)).HasPrivateKey: &lt;/p&gt;
{new X509Certificate2(cert.Export(X509ContentType.Cert)).HasPrivateKey}
&lt;p&gt;&quot;);&lt;br/&gt;
            Console.WriteLine($&quot;new X509Certificate2(cert.RawData).HasPrivateKey: &lt;/p&gt;
{new X509Certificate2(cert.RawData).HasPrivateKey}
&lt;p&gt;&quot;);&lt;br/&gt;
            Console.WriteLine();&lt;br/&gt;
            Console.WriteLine($&quot;new X509Certificate2(cert.Handle).HasPrivateKey: &lt;/p&gt;
{new X509Certificate2(cert.Handle).HasPrivateKey}
&lt;p&gt;&quot;);&lt;br/&gt;
            Console.WriteLine($&quot;new X509Certificate2(cert.Export(X509ContentType.Pfx)).HasPrivateKey: &lt;/p&gt;
{new X509Certificate2(cert.Export(X509ContentType.Pfx)).HasPrivateKey}
&lt;p&gt;&quot;);&lt;br/&gt;
            Console.WriteLine($&quot;new X509Certificate2(cert.Export(X509ContentType.Pkcs12)).HasPrivateKey: &lt;/p&gt;
{new X509Certificate2(cert.Export(X509ContentType.Pkcs12)).HasPrivateKey}
&lt;p&gt;&quot;);&lt;/p&gt;

&lt;p&gt;            Console.ReadLine();&lt;br/&gt;
        }&lt;br/&gt;
    }&lt;br/&gt;
}}}&lt;/p&gt;


&lt;p&gt;Output:&lt;br/&gt;
{{cert.HasPrivateKey: True&lt;/p&gt;

&lt;p&gt;new X509Certificate2(cert.Export(X509ContentType.Cert)).HasPrivateKey: False&lt;br/&gt;
new X509Certificate2(cert.RawData).HasPrivateKey: False&lt;/p&gt;

&lt;p&gt;new X509Certificate2(cert.Handle).HasPrivateKey: True&lt;br/&gt;
new X509Certificate2(cert.Export(X509ContentType.Pfx)).HasPrivateKey: True&lt;br/&gt;
new X509Certificate2(cert.Export(X509ContentType.Pkcs12)).HasPrivateKey: True}}&lt;/p&gt;

</description>
                <environment></environment>
        <key id="353176">CSHARP-1914</key>
            <summary>Certificate Private Keys being dropped</summary>
                <type id="1" iconUrl="https://jira.mongodb.org/secure/viewavatar?size=xsmall&amp;avatarId=14703&amp;avatarType=issuetype">Bug</type>
                                            <priority id="3" iconUrl="https://jira.mongodb.org/images/icons/priorities/major.svg">Major - P3</priority>
                        <status id="6" iconUrl="https://jira.mongodb.org/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="success"/>
                                    <resolution id="9">Done</resolution>
                                        <assignee username="robert@mongodb.com">Robert Stam</assignee>
                                    <reporter username="adawes">Alex Dawes</reporter>
                        <labels>
                    </labels>
                <created>Fri, 10 Feb 2017 09:05:32 +0000</created>
                <updated>Tue, 7 Mar 2017 22:02:41 +0000</updated>
                            <resolved>Tue, 7 Mar 2017 22:02:41 +0000</resolved>
                                    <version>2.3</version>
                                    <fixVersion>2.4.3</fixVersion>
                                    <component>Connectivity</component>
                    <component>Security</component>
                                        <votes>0</votes>
                                    <watches>4</watches>
                                                                                                                <comments>
                            <comment id="1518360" author="xgen-internal-githook" created="Tue, 7 Mar 2017 22:02:03 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{u&apos;username&apos;: u&apos;rstam&apos;, u&apos;name&apos;: u&apos;rstam&apos;, u&apos;email&apos;: u&apos;robert@robertstam.org&apos;}
&lt;p&gt;Message: &lt;a href=&quot;https://jira.mongodb.org/browse/CSHARP-1914&quot; title=&quot;Certificate Private Keys being dropped&quot; class=&quot;issue-link&quot; data-issue-key=&quot;CSHARP-1914&quot;&gt;&lt;del&gt;CSHARP-1914&lt;/del&gt;&lt;/a&gt;: Added Alex Dawes to the contributor list.&lt;br/&gt;
Branch: master&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-csharp-driver/commit/90698a173a07bbbc8b4efc8d39d66d708390b645&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-csharp-driver/commit/90698a173a07bbbc8b4efc8d39d66d708390b645&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="1518359" author="xgen-internal-githook" created="Tue, 7 Mar 2017 22:02:02 +0000"  >&lt;p&gt;Author:&lt;/p&gt;
{u&apos;name&apos;: u&apos;Alexander Dawes&apos;, u&apos;email&apos;: u&apos;a.dawes@winton.com&apos;}
&lt;p&gt;Message: &lt;a href=&quot;https://jira.mongodb.org/browse/CSHARP-1914&quot; title=&quot;Certificate Private Keys being dropped&quot; class=&quot;issue-link&quot; data-issue-key=&quot;CSHARP-1914&quot;&gt;&lt;del&gt;CSHARP-1914&lt;/del&gt;&lt;/a&gt; Remove cloning of the certificates, as this was problematic as the private key is not included in the RawData of a cert and a cert cannot always be cloned in a deep manner (if it is non exportable)&lt;br/&gt;
Branch: master&lt;br/&gt;
&lt;a href=&quot;https://github.com/mongodb/mongo-csharp-driver/commit/53383f27ded6cccd8a0f631b9736d2a7422f9ec2&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-csharp-driver/commit/53383f27ded6cccd8a0f631b9736d2a7422f9ec2&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="1517976" author="adawes" created="Tue, 7 Mar 2017 17:03:21 +0000"  >&lt;p&gt;Created PR: &lt;a href=&quot;https://github.com/mongodb/mongo-csharp-driver/pull/271&quot; class=&quot;external-link&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener&quot;&gt;https://github.com/mongodb/mongo-csharp-driver/pull/271&lt;/a&gt;&lt;/p&gt;</comment>
                            <comment id="1517958" author="rstam" created="Tue, 7 Mar 2017 16:55:44 +0000"  >&lt;p&gt;Go ahead and submit a pull request that removes cloning the X509 certificates.&lt;/p&gt;

&lt;p&gt;Thanks.&lt;/p&gt;</comment>
                            <comment id="1517930" author="adawes" created="Tue, 7 Mar 2017 16:39:57 +0000"  >&lt;p&gt;As another nail in the coffin against trying to perform a shallow clone, I have been unable to get this to work on a Linux machine. Works fine on Windows, but I could not get the driver to create a successful connection after cloning using the IntPtr handle.&lt;/p&gt;</comment>
                            <comment id="1517856" author="adawes" created="Tue, 7 Mar 2017 15:51:44 +0000"  >&lt;p&gt;Just testing my changes on a Linux machine now (works fine on Windows). I&apos;ve tried two separate solutions, firstly not cloning and secondly doing a shallow clone using the X509Certificate2(IntPtr) constructor (which is closer to the original functionality using X509Certificate2(X509Certificate2) constructor which did only a shallow clone anyway). Im happy to put  in a PR for either option - whichever you would prefer..&lt;/p&gt;</comment>
                            <comment id="1517821" author="rstam" created="Tue, 7 Mar 2017 15:31:50 +0000"  >&lt;p&gt;I&apos;m starting to think that the best solution might be to &lt;b&gt;not&lt;/b&gt; clone the certificates.&lt;/p&gt;

&lt;p&gt;While the intention is good (i.e. preserve the immutability of the SslSettings class), if we can&apos;t be sure that we can clone the certificates reliably it is better not to.&lt;/p&gt;

&lt;p&gt;Better for SslSettings to have partial mutability than for it to have reliability problems.&lt;/p&gt;

&lt;p&gt;This would then become a documentation task: we would document that once a certificate has been attached to an SslSettings instance the application should not modify that certificate in any way.&lt;/p&gt;</comment>
                            <comment id="1517623" author="adawes" created="Tue, 7 Mar 2017 09:37:41 +0000"  >&lt;p&gt;Apologies - been distracted the last week but I intend to get this fixed today. Looks like the X509Certificate2(X509Certificate2) constructor originally used only performs a shallow clone anyway, so I am going to simply remove it.&lt;/p&gt;


&lt;p&gt;            var origCert = new X509Certificate2(@&quot;J:\GIT\GITHUB\mongo-csharp-driver\tests\MongoDB.Driver.Tests\testcert.pfx&quot;, &quot;password&quot;);&lt;br/&gt;
            origCert.FriendlyName = &quot;Foo&quot;;&lt;/p&gt;

&lt;p&gt;            var clone1 = new X509Certificate2(origCert);&lt;br/&gt;
            var clone2 = new X509Certificate2(origCert.Handle);&lt;/p&gt;

&lt;p&gt;            Console.WriteLine(origCert.FriendlyName);&lt;br/&gt;
            Console.WriteLine(clone1.FriendlyName);&lt;br/&gt;
            Console.WriteLine(clone2.FriendlyName);&lt;/p&gt;

&lt;p&gt;            origCert.FriendlyName = &quot;Bar&quot;;&lt;/p&gt;

&lt;p&gt;            Console.WriteLine(origCert.FriendlyName);&lt;br/&gt;
            Console.WriteLine(clone1.FriendlyName);&lt;br/&gt;
            Console.WriteLine(clone2.FriendlyName);&lt;/p&gt;

&lt;p&gt;            Console.ReadLine();&lt;/p&gt;</comment>
                            <comment id="1496878" author="adawes" created="Fri, 10 Feb 2017 16:39:48 +0000"  >&lt;p&gt;Possibly you could do the following:&lt;/p&gt;

&lt;p&gt;                try&lt;/p&gt;
                {
                    //If the original certificate is not exportable, calling export will fail.
                    return new X509Certificate2(certificate2.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.Exportable);
                }
&lt;p&gt;                catch&lt;/p&gt;
                {
                    return certificate2;
                }

&lt;p&gt;This isnt very nice though, as you are not always cloning the certificate (if it is not exportable and cant be cloned, then the returned cert is not a copy).&lt;/p&gt;</comment>
                            <comment id="1496874" author="adawes" created="Fri, 10 Feb 2017 16:36:41 +0000"  >&lt;p&gt;Unfortunately the above isn&apos;t true - the handle references the entire certificate in memory, so the clone has the same underlying memory for all properties:&lt;/p&gt;

&lt;p&gt;            var cert = new X509Certificate2(certificate, passphrase, X509KeyStorageFlags.Exportable);&lt;br/&gt;
            cert.FriendlyName = &quot;foo&quot;;&lt;br/&gt;
            var clone = new X509Certificate2(cert.Handle);&lt;br/&gt;
            Console.WriteLine($&quot;cert.FriendlyName: &lt;/p&gt;
{cert.FriendlyName}, clone.FriendlyName: {clone.FriendlyName}&quot;);&lt;br/&gt;
            cert.FriendlyName = &quot;bar&quot;;&lt;br/&gt;
            Console.WriteLine($&quot;cert.FriendlyName: {cert.FriendlyName}
&lt;p&gt;, clone.FriendlyName: &lt;/p&gt;
{clone.FriendlyName}
&lt;p&gt;&quot;);&lt;br/&gt;
            Console.ReadLine();&lt;/p&gt;

&lt;p&gt;Output:&lt;br/&gt;
cert.FriendlyName: foo, clone.FriendlyName: foo&lt;br/&gt;
cert.FriendlyName: bar, clone.FriendlyName: bar&lt;/p&gt;</comment>
                            <comment id="1496860" author="adawes" created="Fri, 10 Feb 2017 16:30:33 +0000"  >&lt;p&gt;I dont know enough about X509Certificate2, but there is a X509Certificate2(IntPtr) constructor. I wonder if the memory pointed to by cert.Handle is the raw data (incl private key) and other mutable properties are then stored elsewhere. If so, then new X509Certificate2(cert.Handle) might provide a way to get a clone with the same private key but..&lt;/p&gt;</comment>
                            <comment id="1496847" author="rstam" created="Fri, 10 Feb 2017 16:15:50 +0000"  >&lt;p&gt;Cloning the certificates is not strictly necessary.&lt;/p&gt;

&lt;p&gt;The reason they are being cloned is because SslSettings is intended to be frozen once it has been fully initialized, but X509Certificate2 is mutable. So to protect itself from external code mutating the certificate the SslSettings class only hands out clones of the certificate.&lt;/p&gt;

&lt;p&gt;If a certificates cannot be successfully cloned we may have to drop our freeze protection a bit.&lt;/p&gt;</comment>
                            <comment id="1496676" author="adawes" created="Fri, 10 Feb 2017 09:10:14 +0000"  >&lt;p&gt;Before I submit a fix for this, can you please explain why cloning the certificates is necessary? Note that using new X509Certificate2(cert.Export(X509ContentType.Pfx)) to clone the certificate is not a perfect fix as if the certificate is not marked as exportable this will break. Not sure if this will also affect X509Certificate usage.&lt;/p&gt;</comment>
                    </comments>
                    <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                        <customfield id="customfield_10011" key="com.atlassian.jira.plugin.system.customfieldtypes:radiobuttons">
                        <customfieldname>Backwards Compatibility</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10038"><![CDATA[Fully Compatible]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                <customfield id="customfield_15850" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummary">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_12550" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>2|hrb14n:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10558" key="com.pyxis.greenhopper.jira:gh-global-rank">
                        <customfieldname>Rank (Obsolete)</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>9223372036854775807</customfieldvalue>
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                    <customfield id="customfield_10557" key="com.pyxis.greenhopper.jira:gh-sprint">
                        <customfieldname>Sprint</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue id="1636">C# Sprint 50</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            </customfields>
    </item>
</channel>
</rss>