Merge pull request #990 from jtattermusch/csharp_tls_server

C# server-side TLS support
pull/1012/head
Tim Emiola 10 years ago
commit 6063b9ff52
  1. 3
      include/grpc/grpc_security.h
  2. 2
      src/csharp/Grpc.Core/Grpc.Core.csproj
  3. 68
      src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
  4. 9
      src/csharp/Grpc.Core/Internal/ServerSafeHandle.cs
  5. 12
      src/csharp/Grpc.Core/Server.cs
  6. 107
      src/csharp/Grpc.Core/ServerCredentials.cs
  7. 1
      src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
  8. 13
      src/csharp/Grpc.IntegrationTesting/InteropClient.cs
  9. 8
      src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs
  10. 12
      src/csharp/Grpc.IntegrationTesting/InteropServer.cs
  11. 83
      src/csharp/Grpc.IntegrationTesting/TestCredentials.cs
  12. 35
      src/csharp/ext/grpc_csharp_ext.c
  13. 4
      tools/dockerfile/grpc_csharp_mono/Dockerfile

@ -167,10 +167,9 @@ grpc_server_credentials *grpc_ssl_server_credentials_create(
grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
void);
/* --- Secure server creation. --- */
/* --- Server-side secure ports. --- */
/* Add a HTTP2 over an encrypted link over tcp listener.
Server must have been created with grpc_secure_server_create.
Returns bound port number on success, 0 on failure.
REQUIRES: server not started */
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,

@ -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

@ -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;
}
}
}

@ -55,6 +55,9 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
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);
@ -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);

@ -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();

@ -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);
}
}
}

@ -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>

@ -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;

@ -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);
}

@ -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();

@ -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});
}
}
}

@ -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,

@ -51,5 +51,5 @@ ADD cacerts cacerts
# Add a service_account directory containing the auth creds file
ADD service_account service_account
# TODO: add command to run the interop server
CMD ["/bin/bash", "-l"]
# Run the C# Interop Server
CMD ["/bin/bash", "-l", "-c", "cd /var/local/git/grpc/src/csharp/Grpc.IntegrationTesting.Server/bin/Debug && mono Grpc.IntegrationTesting.Server.exe --use_tls=true --port=8070"]

Loading…
Cancel
Save