CurtHagenlocher commented on code in PR #3303:
URL: https://github.com/apache/arrow-adbc/pull/3303#discussion_r2291605366


##########
csharp/src/Drivers/Apache/Hive2/HiveServer2StandardConnection.cs:
##########
@@ -112,19 +112,15 @@ protected override TTransport CreateTransport()
             TTransport baseTransport;
             if (TlsOptions.IsTlsEnabled)
             {
-                X509Certificate2? trustedCert = 
!string.IsNullOrEmpty(TlsOptions.TrustedCertificatePath)
-                    ? new X509Certificate2(TlsOptions.TrustedCertificatePath!)
-                    : null;
-
                 RemoteCertificateValidationCallback certValidator = (sender, 
cert, chain, errors) => HiveServer2TlsImpl.ValidateCertificate(cert, errors, 
TlsOptions);
 
                 if (IPAddress.TryParse(hostName!, out var ipAddress))
                 {
-                    baseTransport = new TTlsSocketTransport(ipAddress, 
portValue, config: new(), 0, trustedCert, certValidator);
+                    baseTransport = new TTlsSocketTransport(ipAddress, 
portValue, config: new(), 0, null, certValidator);

Review Comment:
   There's similar code in ImpalaStandardConnection.cs. Does that need to be 
updated as well?



##########
csharp/src/Drivers/Apache/Hive2/HiveServer2TlsImpl.cs:
##########
@@ -155,14 +180,39 @@ static internal bool ValidateCertificate(X509Certificate? 
cert, SslPolicyErrors
                 return 
!policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) || 
(tlsProperties.AllowSelfSigned && IsSelfSigned(cert2));
             }
 
-            X509Certificate2 trustedRoot = new 
X509Certificate2(tlsProperties.TrustedCertificatePath);
             X509Chain customChain = new();
-            customChain.ChainPolicy.ExtraStore.Add(trustedRoot);
             // "tell the X509Chain class that I do trust this root certs and 
it should check just the certs in the chain and nothing else"
             customChain.ChainPolicy.VerificationFlags = 
X509VerificationFlags.AllowUnknownCertificateAuthority;
+            var collection = 
LoadPemCertificates(tlsProperties.TrustedCertificatePath!);
+
+            foreach (var trustedCert in collection)
+            {
+                customChain.ChainPolicy.ExtraStore.Add(trustedCert);
+            }
             customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
 
             bool chainValid = customChain.Build(cert2);
+            if (chainValid)
+            {
+                bool trustedBy = false;
+                foreach (X509ChainElement element in customChain.ChainElements)
+                {
+                    foreach (X509Certificate2 ca in collection)

Review Comment:
   I know that cert chains typically aren't *that* long, but this is n^2 
behavior. Is it worth loading the certificates as a dictionary keyed by 
thumbprint in order to speed up the search?



##########
csharp/src/Drivers/Apache/Hive2/HiveServer2TlsImpl.cs:
##########
@@ -138,6 +139,30 @@ static internal TlsProperties 
GetStandardTlsOptions(IReadOnlyDictionary<string,
             return tlsProperties;
         }
 
+        public static List<X509Certificate2> LoadPemCertificates(string 
pemPath)

Review Comment:
   How big is this file typically, and how long does it take to read and parse? 
Does it make sense to keep a cache of these by file path and size/last update 
time so that it doesn't need to be reloaded regularly?
   
   The standard ~cacert.pem is about 220kb.



##########
csharp/src/Drivers/Apache/Hive2/HiveServer2TlsImpl.cs:
##########
@@ -155,14 +180,39 @@ static internal bool ValidateCertificate(X509Certificate? 
cert, SslPolicyErrors
                 return 
!policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) || 
(tlsProperties.AllowSelfSigned && IsSelfSigned(cert2));
             }
 
-            X509Certificate2 trustedRoot = new 
X509Certificate2(tlsProperties.TrustedCertificatePath);
             X509Chain customChain = new();
-            customChain.ChainPolicy.ExtraStore.Add(trustedRoot);
             // "tell the X509Chain class that I do trust this root certs and 
it should check just the certs in the chain and nothing else"
             customChain.ChainPolicy.VerificationFlags = 
X509VerificationFlags.AllowUnknownCertificateAuthority;
+            var collection = 
LoadPemCertificates(tlsProperties.TrustedCertificatePath!);
+
+            foreach (var trustedCert in collection)
+            {
+                customChain.ChainPolicy.ExtraStore.Add(trustedCert);
+            }
             customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
 
             bool chainValid = customChain.Build(cert2);
+            if (chainValid)
+            {
+                bool trustedBy = false;
+                foreach (X509ChainElement element in customChain.ChainElements)
+                {
+                    foreach (X509Certificate2 ca in collection)
+                    {
+                        if (element.Certificate.Thumbprint == ca.Thumbprint)

Review Comment:
   Should this be a case-insensitive comparison or are thumbprints always 
normalized to a specific case? Is comparing just the thumbprint enough for good 
security?



##########
csharp/src/Drivers/Apache/Hive2/HiveServer2TlsImpl.cs:
##########
@@ -155,14 +180,39 @@ static internal bool ValidateCertificate(X509Certificate? 
cert, SslPolicyErrors
                 return 
!policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors) || 
(tlsProperties.AllowSelfSigned && IsSelfSigned(cert2));
             }
 
-            X509Certificate2 trustedRoot = new 
X509Certificate2(tlsProperties.TrustedCertificatePath);
             X509Chain customChain = new();
-            customChain.ChainPolicy.ExtraStore.Add(trustedRoot);
             // "tell the X509Chain class that I do trust this root certs and 
it should check just the certs in the chain and nothing else"
             customChain.ChainPolicy.VerificationFlags = 
X509VerificationFlags.AllowUnknownCertificateAuthority;
+            var collection = 
LoadPemCertificates(tlsProperties.TrustedCertificatePath!);
+
+            foreach (var trustedCert in collection)
+            {
+                customChain.ChainPolicy.ExtraStore.Add(trustedCert);
+            }
             customChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
 
             bool chainValid = customChain.Build(cert2);
+            if (chainValid)
+            {
+                bool trustedBy = false;
+                foreach (X509ChainElement element in customChain.ChainElements)
+                {
+                    foreach (X509Certificate2 ca in collection)
+                    {
+                        if (element.Certificate.Thumbprint == ca.Thumbprint)
+                        {
+                            trustedBy = true;
+                            break;
+                        }
+                    }
+                    if (trustedBy)
+                    {
+                        break;
+                    }
+                }
+                chainValid = chainValid && trustedBy;
+            }
+
             return chainValid || (tlsProperties.AllowSelfSigned && 
IsSelfSigned(cert2));

Review Comment:
   Consider modifying the check around line 178 to return early for a 
self-signed certificate even if `TrustedCertificatePath` is not null. There's 
no reason to go to the trouble of loading the additional certificates if we 
already know we have a self-signed cert. Then the check here becomes 
superfluous and can be removed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscr...@arrow.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org

Reply via email to