aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
authorGravatar Jan Tattermusch <jtattermusch@google.com>2015-03-03 09:30:55 -0800
committerGravatar Jan Tattermusch <jtattermusch@google.com>2015-03-09 16:05:05 -0700
commitb0829ebaf174216787c9a9557cf4a40afa2c8023 (patch)
treef392cff9c5341a9e765aec6a161c8d4025a7dff5 /src/csharp
parent874e53ad2d61ae3846a4a9672eb871cc51bb0c84 (diff)
C# server side TLS support
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/Grpc.Core/Grpc.Core.csproj2
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs68
-rw-r--r--src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs9
-rw-r--r--src/csharp/Grpc.Core/Server.cs12
-rw-r--r--src/csharp/Grpc.Core/ServerCredentials.cs107
-rw-r--r--src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj1
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClient.cs13
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs8
-rw-r--r--src/csharp/Grpc.IntegrationTesting/InteropServer.cs12
-rw-r--r--src/csharp/Grpc.IntegrationTesting/TestCredentials.cs83
-rw-r--r--src/csharp/ext/grpc_csharp_ext.c35
11 files changed, 333 insertions, 17 deletions
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 78b6cdde59..c4b12b1cab 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -74,6 +74,8 @@
<Compile Include="OperationFailedException.cs" />
<Compile Include="Internal\AsyncCall.cs" />
<Compile Include="Utils\Preconditions.cs" />
+ <Compile Include="Internal\ServerCredentialsSafeHandle.cs" />
+ <Compile Include="ServerCredentials.cs" />
</ItemGroup>
<Choose>
<!-- Under older versions of Monodevelop, Choose is not supported and is just
diff --git a/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
new file mode 100644
index 0000000000..961180741a
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
@@ -0,0 +1,68 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Grpc.Core.Utils;
+
+namespace Grpc.Core.Internal
+{
+ /// <summary>
+ /// grpc_server_credentials from <grpc/grpc_security.h>
+ /// </summary>
+ internal class ServerCredentialsSafeHandle : SafeHandleZeroIsInvalid
+ {
+ [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
+ static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs);
+
+ [DllImport("grpc_csharp_ext.dll")]
+ static extern void grpcsharp_server_credentials_release(IntPtr credentials);
+
+ private ServerCredentialsSafeHandle()
+ {
+ }
+
+ public static ServerCredentialsSafeHandle CreateSslCredentials(string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray)
+ {
+ Preconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
+ return grpcsharp_ssl_server_credentials_create(null,
+ keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
+ new UIntPtr((ulong)keyCertPairCertChainArray.Length));
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ grpcsharp_server_credentials_release(handle);
+ return true;
+ }
+ }
+}
diff --git a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
index de9bbaf7c1..b5a5ae4976 100644
--- a/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
@@ -56,6 +56,9 @@ namespace Grpc.Core.Internal
static extern Int32 grpcsharp_server_add_http2_port(ServerSafeHandle server, string addr);
[DllImport("grpc_csharp_ext.dll")]
+ static extern Int32 grpcsharp_server_add_secure_http2_port(ServerSafeHandle server, string addr, ServerCredentialsSafeHandle creds);
+
+ [DllImport("grpc_csharp_ext.dll")]
static extern void grpcsharp_server_start(ServerSafeHandle server);
[DllImport("grpc_csharp_ext.dll")]
@@ -74,7 +77,6 @@ namespace Grpc.Core.Internal
public static ServerSafeHandle NewServer(CompletionQueueSafeHandle cq, IntPtr args)
{
- // TODO: also grpc_secure_server_create...
return grpcsharp_server_create(cq, args);
}
@@ -83,6 +85,11 @@ namespace Grpc.Core.Internal
return grpcsharp_server_add_http2_port(this, addr);
}
+ public int AddPort(string addr, ServerCredentialsSafeHandle credentials)
+ {
+ return grpcsharp_server_add_secure_http2_port(this, addr, credentials);
+ }
+
public void Start()
{
grpcsharp_server_start(this);
diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs
index 152cc2176c..cafdb3b663 100644
--- a/src/csharp/Grpc.Core/Server.cs
+++ b/src/csharp/Grpc.Core/Server.cs
@@ -75,10 +75,20 @@ namespace Grpc.Core
}
// only call before Start()
- public int AddPort(string addr) {
+ public int AddPort(string addr)
+ {
return handle.AddPort(addr);
}
+ // only call before Start()
+ public int AddPort(string addr, ServerCredentials credentials)
+ {
+ using (var nativeCredentials = credentials.ToNativeCredentials())
+ {
+ return handle.AddPort(addr, nativeCredentials);
+ }
+ }
+
public void Start()
{
handle.Start();
diff --git a/src/csharp/Grpc.Core/ServerCredentials.cs b/src/csharp/Grpc.Core/ServerCredentials.cs
new file mode 100644
index 0000000000..1372e61fa7
--- /dev/null
+++ b/src/csharp/Grpc.Core/ServerCredentials.cs
@@ -0,0 +1,107 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Grpc.Core.Internal;
+
+namespace Grpc.Core
+{
+ public abstract class ServerCredentials
+ {
+ /// <summary>
+ /// Creates native object for the credentials.
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal abstract ServerCredentialsSafeHandle ToNativeCredentials();
+ }
+
+ /// <summary>
+ /// Key certificate pair (in PEM encoding).
+ /// </summary>
+ public class KeyCertificatePair
+ {
+ string certChain;
+ string privateKey;
+
+ public KeyCertificatePair(string certChain, string privateKey)
+ {
+ this.certChain = certChain;
+ this.privateKey = privateKey;
+ }
+
+ public string CertChain
+ {
+ get
+ {
+ return certChain;
+ }
+ }
+
+ public string PrivateKey
+ {
+ get
+ {
+ return privateKey;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Server-side SSL credentials.
+ /// </summary>
+ public class SslServerCredentials : ServerCredentials
+ {
+ // TODO: immutable list...
+ List<KeyCertificatePair> keyCertPairs;
+
+ public SslServerCredentials(List<KeyCertificatePair> keyCertPairs)
+ {
+ this.keyCertPairs = keyCertPairs;
+ }
+
+ internal override ServerCredentialsSafeHandle ToNativeCredentials()
+ {
+ int count = keyCertPairs.Count;
+ string[] certChains = new string[count];
+ string[] keys = new string[count];
+ for (int i = 0; i < count; i++)
+ {
+ certChains[i] = keyCertPairs[i].CertChain;
+ keys[i] = keyCertPairs[i].PrivateKey;
+ }
+ return ServerCredentialsSafeHandle.CreateSslCredentials(certChains, keys);
+ }
+ }
+}
+
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index 8f7a17efcb..438bf9e95d 100644
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -49,6 +49,7 @@
<Compile Include="TestServiceImpl.cs" />
<Compile Include="InteropServer.cs" />
<Compile Include="InteropClient.cs" />
+ <Compile Include="TestCredentials.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
index 30301f165b..2992c42ae9 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs
@@ -51,7 +51,7 @@ namespace Grpc.IntegrationTesting
{
public bool help;
public string serverHost= "127.0.0.1";
- public string serverHostOverride = "foo.test.google.fr";
+ public string serverHostOverride = TestCredentials.DefaultHostOverride;
public int? serverPort;
public string testCase = "large_unary";
public bool useTls;
@@ -103,16 +103,7 @@ namespace Grpc.IntegrationTesting
Credentials credentials = null;
if (options.useTls)
{
- string caPath = "data/ca.pem"; // Default testing CA
- if (!options.useTestCa)
- {
- caPath = Environment.GetEnvironmentVariable("SSL_CERT_FILE");
- if (string.IsNullOrEmpty(caPath))
- {
- throw new ArgumentException("CA path environment variable is not set.");
- }
- }
- credentials = new SslCredentials(File.ReadAllText(caPath));
+ credentials = TestCredentials.CreateTestClientCredentials(options.useTestCa);
}
ChannelArgs channelArgs = null;
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
index 4bb0b9ee51..ab2d6f4a6a 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
@@ -59,9 +59,13 @@ namespace Grpc.IntegrationTesting
server = new Server();
server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl()));
- int port = server.AddPort(host + ":0");
+ int port = server.AddPort(host + ":0", TestCredentials.CreateTestServerCredentials());
server.Start();
- channel = new Channel(host + ":" + port);
+
+ var channelArgs = ChannelArgs.NewBuilder()
+ .AddString(ChannelArgs.SslTargetNameOverrideKey, TestCredentials.DefaultHostOverride).Build();
+
+ channel = new Channel(host + ":" + port, TestCredentials.CreateTestClientCredentials(true), channelArgs);
client = TestServiceGrpc.NewStub(channel);
}
diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
index a25d3b3530..24d72da0c3 100644
--- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
+++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs
@@ -34,6 +34,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Google.ProtocolBuffers;
@@ -49,7 +50,7 @@ namespace Grpc.IntegrationTesting
private class ServerOptions
{
public bool help;
- public int? port;
+ public int? port = 8070;
public bool useTls;
}
@@ -93,7 +94,14 @@ namespace Grpc.IntegrationTesting
server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl()));
string addr = "0.0.0.0:" + options.port;
- server.AddPort(addr);
+ if (options.useTls)
+ {
+ server.AddPort(addr, TestCredentials.CreateTestServerCredentials());
+ }
+ else
+ {
+ server.AddPort(addr);
+ }
Console.WriteLine("Running server on " + addr);
server.Start();
diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
new file mode 100644
index 0000000000..b31abf1181
--- /dev/null
+++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
@@ -0,0 +1,83 @@
+#region Copyright notice and license
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Google.ProtocolBuffers;
+using Grpc.Core;
+using Grpc.Core.Utils;
+using NUnit.Framework;
+using grpc.testing;
+
+namespace Grpc.IntegrationTesting
+{
+ /// <summary>
+ /// SSL Credentials for testing.
+ /// </summary>
+ public static class TestCredentials
+ {
+ public const string DefaultHostOverride = "foo.test.google.fr";
+
+ public const string ClientCertAuthorityPath = "data/ca.pem";
+ public const string ClientCertAuthorityEnvName = "SSL_CERT_FILE";
+
+ public const string ServerCertChainPath = "data/server1.pem";
+ public const string ServerPrivateKeyPath = "data/server1.key";
+
+ public static SslCredentials CreateTestClientCredentials(bool useTestCa)
+ {
+ string caPath = ClientCertAuthorityPath;
+ if (!useTestCa)
+ {
+ caPath = Environment.GetEnvironmentVariable(ClientCertAuthorityEnvName);
+ if (string.IsNullOrEmpty(caPath))
+ {
+ throw new ArgumentException("CA path environment variable is not set.");
+ }
+ }
+ return new SslCredentials(File.ReadAllText(caPath));
+ }
+
+ public static SslServerCredentials CreateTestServerCredentials()
+ {
+ var keyCertPair = new KeyCertificatePair(
+ File.ReadAllText(ServerCertChainPath),
+ File.ReadAllText(ServerPrivateKeyPath));
+ return new SslServerCredentials(new List<KeyCertificatePair> {keyCertPair});
+ }
+ }
+}
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index e24438704c..51abb632f7 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -653,6 +653,41 @@ grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target,
return grpc_secure_channel_create(creds, target, args);
}
+GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE
+grpcsharp_ssl_server_credentials_create(
+ const char *pem_root_certs, const char **key_cert_pair_cert_chain_array,
+ const char **key_cert_pair_private_key_array, size_t num_key_cert_pairs) {
+ size_t i;
+ grpc_server_credentials *creds;
+ grpc_ssl_pem_key_cert_pair *key_cert_pairs =
+ gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
+ memset(key_cert_pairs, 0,
+ sizeof(grpc_ssl_pem_key_cert_pair) * num_key_cert_pairs);
+
+ for (i = 0; i < num_key_cert_pairs; i++) {
+ if (key_cert_pair_cert_chain_array[i] ||
+ key_cert_pair_private_key_array[i]) {
+ key_cert_pairs[i].cert_chain = key_cert_pair_cert_chain_array[i];
+ key_cert_pairs[i].private_key = key_cert_pair_private_key_array[i];
+ }
+ }
+ creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs,
+ num_key_cert_pairs);
+ gpr_free(key_cert_pairs);
+ return creds;
+}
+
+GPR_EXPORT void grpcsharp_server_credentials_release(
+ grpc_server_credentials *creds) {
+ grpc_server_credentials_release(creds);
+}
+
+GPR_EXPORT gpr_int32 GPR_CALLTYPE
+grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr,
+ grpc_server_credentials *creds) {
+ return grpc_server_add_secure_http2_port(server, addr, creds);
+}
+
/* Logging */
typedef void(GPR_CALLTYPE *grpcsharp_log_func)(const char *file, gpr_int32 line,