diff options
author | Jan Tattermusch <jtattermusch@google.com> | 2015-03-03 09:30:55 -0800 |
---|---|---|
committer | Jan Tattermusch <jtattermusch@google.com> | 2015-03-09 16:05:05 -0700 |
commit | b0829ebaf174216787c9a9557cf4a40afa2c8023 (patch) | |
tree | f392cff9c5341a9e765aec6a161c8d4025a7dff5 /src/csharp | |
parent | 874e53ad2d61ae3846a4a9672eb871cc51bb0c84 (diff) |
C# server side TLS support
Diffstat (limited to 'src/csharp')
-rw-r--r-- | src/csharp/Grpc.Core/Grpc.Core.csproj | 2 | ||||
-rw-r--r-- | src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs | 68 | ||||
-rw-r--r-- | src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs | 9 | ||||
-rw-r--r-- | src/csharp/Grpc.Core/Server.cs | 12 | ||||
-rw-r--r-- | src/csharp/Grpc.Core/ServerCredentials.cs | 107 | ||||
-rw-r--r-- | src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj | 1 | ||||
-rw-r--r-- | src/csharp/Grpc.IntegrationTesting/InteropClient.cs | 13 | ||||
-rw-r--r-- | src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs | 8 | ||||
-rw-r--r-- | src/csharp/Grpc.IntegrationTesting/InteropServer.cs | 12 | ||||
-rw-r--r-- | src/csharp/Grpc.IntegrationTesting/TestCredentials.cs | 83 | ||||
-rw-r--r-- | src/csharp/ext/grpc_csharp_ext.c | 35 |
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, |