Expose certificate request type in SslServerCredentials.

pull/16552/head
Jan Tattermusch 7 years ago
parent cd74b357e1
commit db0e21a5cb
  1. 6
      src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs
  2. 4
      src/csharp/Grpc.Core/Internal/ServerCredentialsSafeHandle.cs
  3. 97
      src/csharp/Grpc.Core/ServerCredentials.cs
  4. 139
      src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs
  5. 6
      src/csharp/ext/grpc_csharp_ext.c
  6. 2
      templates/src/csharp/Grpc.Core/Internal/NativeMethods.Generated.cs.template

@ -505,7 +505,7 @@ namespace Grpc.Core.Internal
public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback); public delegate void grpcsharp_redirect_log_delegate(GprLogDelegate callback);
public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor); public delegate CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin_delegate(NativeMetadataInterceptor interceptor);
public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); public delegate void grpcsharp_metadata_credentials_notify_from_plugin_delegate(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth); public delegate ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create_delegate(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials); public delegate void grpcsharp_server_credentials_release_delegate(IntPtr credentials);
public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args); public delegate ServerSafeHandle grpcsharp_server_create_delegate(ChannelArgsSafeHandle args);
public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq); public delegate void grpcsharp_server_register_completion_queue_delegate(ServerSafeHandle server, CompletionQueueSafeHandle cq);
@ -752,7 +752,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
[DllImport(ImportName)] [DllImport(ImportName)]
public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth); public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
[DllImport(ImportName)] [DllImport(ImportName)]
public static extern void grpcsharp_server_credentials_release(IntPtr credentials); public static extern void grpcsharp_server_credentials_release(IntPtr credentials);
@ -1045,7 +1045,7 @@ namespace Grpc.Core.Internal
public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails); public static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
[DllImport(ImportName)] [DllImport(ImportName)]
public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth); public static extern ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest);
[DllImport(ImportName)] [DllImport(ImportName)]
public static extern void grpcsharp_server_credentials_release(IntPtr credentials); public static extern void grpcsharp_server_credentials_release(IntPtr credentials);

@ -32,13 +32,13 @@ namespace Grpc.Core.Internal
{ {
} }
public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, bool forceClientAuth) public static ServerCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, SslClientCertificateRequestType clientCertificateRequest)
{ {
GrpcPreconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length); GrpcPreconditions.CheckArgument(keyCertPairCertChainArray.Length == keyCertPairPrivateKeyArray.Length);
return Native.grpcsharp_ssl_server_credentials_create(pemRootCerts, return Native.grpcsharp_ssl_server_credentials_create(pemRootCerts,
keyCertPairCertChainArray, keyCertPairPrivateKeyArray, keyCertPairCertChainArray, keyCertPairPrivateKeyArray,
new UIntPtr((ulong)keyCertPairCertChainArray.Length), new UIntPtr((ulong)keyCertPairCertChainArray.Length),
forceClientAuth ? 1 : 0); clientCertificateRequest);
} }
protected override bool ReleaseHandle() protected override bool ReleaseHandle()

@ -57,6 +57,60 @@ namespace Grpc.Core
} }
} }
/// <summary>
/// Modes of requesting client's SSL certificate by the server.
/// Corresponds to <c>grpc_ssl_client_certificate_request_type</c>.
/// </summary>
public enum SslClientCertificateRequestType {
/// <summary>
/// Server does not request client certificate.
/// The certificate presented by the client is not checked by the server at
/// all. (A client may present a self signed or signed certificate or not
/// present a certificate at all and any of those option would be accepted)
/// </summary>
DontRequestClientCertificate = 0,
/// <summary>
/// Server requests client certificate but does not enforce that the client
/// presents a certificate.
/// If the client presents a certificate, the client authentication is left to
/// the application (the necessary metadata will be available to the
/// application via authentication context properties, see grpc_auth_context).
/// The client's key certificate pair must be valid for the SSL connection to
/// be established.
///</summary>
RequestClientCertificateButDontVerify,
/// <summary>
/// Server requests client certificate but does not enforce that the client
/// presents a certificate.
/// If the client presents a certificate, the client authentication is done by
/// the gRPC framework. (For a successful connection the client needs to either
/// present a certificate that can be verified against the root certificate
/// configured by the server or not present a certificate at all)
/// The client's key certificate pair must be valid for the SSL connection to
/// be established.
/// </summary>
RequestClientCertificateAndVerify,
/// <summary>
/// Server requests client certificate and enforces that the client presents a
/// certificate.
/// If the client presents a certificate, the client authentication is left to
/// the application (the necessary metadata will be available to the
/// application via authentication context properties, see grpc_auth_context).
/// The client's key certificate pair must be valid for the SSL connection to
/// be established.
///</summary>
RequestAndRequireClientCertificateButDontVerify,
/// <summary>
/// Server requests client certificate and enforces that the client presents a
/// certificate.
/// The cerificate presented by the client is verified by the gRPC framework.
/// (For a successful connection the client needs to present a certificate that
/// can be verified against the root certificate configured by the server)
/// The client's key certificate pair must be valid for the SSL connection to
/// be established.
/// </summary>
RequestAndRequireClientCertificateAndVerify,
}
/// <summary> /// <summary>
/// Server-side SSL credentials. /// Server-side SSL credentials.
/// </summary> /// </summary>
@ -64,35 +118,45 @@ namespace Grpc.Core
{ {
readonly IList<KeyCertificatePair> keyCertificatePairs; readonly IList<KeyCertificatePair> keyCertificatePairs;
readonly string rootCertificates; readonly string rootCertificates;
readonly bool forceClientAuth; readonly SslClientCertificateRequestType clientCertificateRequest;
/// <summary> /// <summary>
/// Creates server-side SSL credentials. /// Creates server-side SSL credentials.
/// </summary> /// </summary>
/// <param name="keyCertificatePairs">Key-certificates to use.</param> /// <param name="keyCertificatePairs">Key-certificates to use.</param>
/// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param> /// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
/// <param name="forceClientAuth">If true, client will be rejected unless it proves its unthenticity using against rootCertificates.</param> /// <param name="forceClientAuth">Deprecated, use clientCertificateRequest overload instead.</param>
public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, bool forceClientAuth) public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, bool forceClientAuth)
: this(keyCertificatePairs, rootCertificates, forceClientAuth ? SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify : SslClientCertificateRequestType.DontRequestClientCertificate)
{
}
/// <summary>
/// Creates server-side SSL credentials.
/// </summary>
/// <param name="keyCertificatePairs">Key-certificates to use.</param>
/// <param name="rootCertificates">PEM encoded client root certificates used to authenticate client.</param>
/// <param name="clientCertificateRequest">Options for requesting and verification of client certificate.</param>
public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs, string rootCertificates, SslClientCertificateRequestType clientCertificateRequest)
{ {
this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly(); this.keyCertificatePairs = new List<KeyCertificatePair>(keyCertificatePairs).AsReadOnly();
GrpcPreconditions.CheckArgument(this.keyCertificatePairs.Count > 0, GrpcPreconditions.CheckArgument(this.keyCertificatePairs.Count > 0,
"At least one KeyCertificatePair needs to be provided."); "At least one KeyCertificatePair needs to be provided.");
if (forceClientAuth) if (clientCertificateRequest == SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify)
{ {
GrpcPreconditions.CheckNotNull(rootCertificates, GrpcPreconditions.CheckNotNull(rootCertificates,
"Cannot force client authentication unless you provide rootCertificates."); "Cannot require and verify client certificate unless you provide rootCertificates.");
} }
this.rootCertificates = rootCertificates; this.rootCertificates = rootCertificates;
this.forceClientAuth = forceClientAuth; this.clientCertificateRequest = clientCertificateRequest;
} }
/// <summary> /// <summary>
/// Creates server-side SSL credentials. /// Creates server-side SSL credentials.
/// This constructor should be use if you do not wish to autheticate client /// This constructor should be use if you do not wish to autheticate client at all.
/// using client root certificates.
/// </summary> /// </summary>
/// <param name="keyCertificatePairs">Key-certificates to use.</param> /// <param name="keyCertificatePairs">Key-certificates to use.</param>
public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, false) public SslServerCredentials(IEnumerable<KeyCertificatePair> keyCertificatePairs) : this(keyCertificatePairs, null, SslClientCertificateRequestType.DontRequestClientCertificate)
{ {
} }
@ -119,13 +183,24 @@ namespace Grpc.Core
} }
/// <summary> /// <summary>
/// If true, the authenticity of client check will be enforced. /// Deprecated. If true, the authenticity of client check will be enforced.
/// </summary> /// </summary>
public bool ForceClientAuthentication public bool ForceClientAuthentication
{ {
get get
{ {
return this.forceClientAuth; return this.clientCertificateRequest == SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify;
}
}
/// <summary>
/// Mode of requesting certificate from client by the server.
/// </summary>
public SslClientCertificateRequestType ClientCertificateRequest
{
get
{
return this.clientCertificateRequest;
} }
} }
@ -139,7 +214,7 @@ namespace Grpc.Core
certChains[i] = keyCertificatePairs[i].CertificateChain; certChains[i] = keyCertificatePairs[i].CertificateChain;
keys[i] = keyCertificatePairs[i].PrivateKey; keys[i] = keyCertificatePairs[i].PrivateKey;
} }
return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, forceClientAuth); return ServerCredentialsSafeHandle.CreateSslCredentials(rootCertificates, certChains, keys, clientCertificateRequest);
} }
} }
} }

@ -37,20 +37,24 @@ namespace Grpc.IntegrationTesting
public class SslCredentialsTest public class SslCredentialsTest
{ {
const string Host = "localhost"; const string Host = "localhost";
const string IsPeerAuthenticatedMetadataKey = "test_only_is_peer_authenticated";
Server server; Server server;
Channel channel; Channel channel;
TestService.TestServiceClient client; TestService.TestServiceClient client;
[OneTimeSetUp] string rootCert;
public void Init() KeyCertificatePair keyCertPair;
public void InitClientAndServer(bool clientAddKeyCertPair,
SslClientCertificateRequestType clientCertRequestType)
{ {
var rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath); rootCert = File.ReadAllText(TestCredentials.ClientCertAuthorityPath);
var keyCertPair = new KeyCertificatePair( keyCertPair = new KeyCertificatePair(
File.ReadAllText(TestCredentials.ServerCertChainPath), File.ReadAllText(TestCredentials.ServerCertChainPath),
File.ReadAllText(TestCredentials.ServerPrivateKeyPath)); File.ReadAllText(TestCredentials.ServerPrivateKeyPath));
var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, true); var serverCredentials = new SslServerCredentials(new[] { keyCertPair }, rootCert, clientCertRequestType);
var clientCredentials = new SslCredentials(rootCert, keyCertPair); var clientCredentials = clientAddKeyCertPair ? new SslCredentials(rootCert, keyCertPair) : new SslCredentials(rootCert);
// Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755 // Disable SO_REUSEPORT to prevent https://github.com/grpc/grpc/issues/10755
server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) server = new Server(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) })
@ -71,20 +75,134 @@ namespace Grpc.IntegrationTesting
[OneTimeTearDown] [OneTimeTearDown]
public void Cleanup() public void Cleanup()
{
if (channel != null)
{ {
channel.ShutdownAsync().Wait(); channel.ShutdownAsync().Wait();
}
if (server != null)
{
server.ShutdownAsync().Wait(); server.ShutdownAsync().Wait();
} }
}
[Test] [Test]
public void AuthenticatedClientAndServer() public async Task NoClientCert_DontRequestClientCertificate_Accepted()
{ {
var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 }); InitClientAndServer(
Assert.AreEqual(10, response.Payload.Body.Length); clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.DontRequestClientCertificate);
await CheckAccepted(expectPeerAuthenticated: false);
} }
[Test] [Test]
public async Task AuthContextIsPopulated() public async Task ClientWithCert_DontRequestClientCertificate_AcceptedButPeerNotAuthenticated()
{
InitClientAndServer(
clientAddKeyCertPair: true,
clientCertRequestType: SslClientCertificateRequestType.DontRequestClientCertificate);
await CheckAccepted(expectPeerAuthenticated: false);
}
[Test]
public async Task NoClientCert_RequestClientCertificateButDontVerify_Accepted()
{
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.RequestClientCertificateButDontVerify);
await CheckAccepted(expectPeerAuthenticated: false);
}
[Test]
public async Task NoClientCert_RequestClientCertificateAndVerify_Accepted()
{
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.RequestClientCertificateAndVerify);
await CheckAccepted(expectPeerAuthenticated: false);
}
[Test]
public async Task ClientWithCert_RequestAndRequireClientCertificateButDontVerify_Accepted()
{
InitClientAndServer(
clientAddKeyCertPair: true,
clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireClientCertificateButDontVerify);
await CheckAccepted(expectPeerAuthenticated: true);
await CheckAuthContextIsPopulated();
}
[Test]
public async Task ClientWithCert_RequestAndRequireClientCertificateAndVerify_Accepted()
{
InitClientAndServer(
clientAddKeyCertPair: true,
clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify);
await CheckAccepted(expectPeerAuthenticated: true);
await CheckAuthContextIsPopulated();
}
[Test]
public void NoClientCert_RequestAndRequireClientCertificateButDontVerify_Rejected()
{
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireClientCertificateButDontVerify);
CheckRejected();
}
[Test]
public void NoClientCert_RequestAndRequireClientCertificateAndVerify_Rejected()
{
InitClientAndServer(
clientAddKeyCertPair: false,
clientCertRequestType: SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify);
CheckRejected();
}
[Test]
public void Constructor_LegacyForceClientAuth()
{
var creds = new SslServerCredentials(new[] { keyCertPair }, rootCert, true);
Assert.AreEqual(SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify, creds.ClientCertificateRequest);
var creds2 = new SslServerCredentials(new[] { keyCertPair }, rootCert, false);
Assert.AreEqual(SslClientCertificateRequestType.DontRequestClientCertificate, creds2.ClientCertificateRequest);
}
[Test]
public void Constructor_NullRootCerts()
{
var keyCertPairs = new[] { keyCertPair };
new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.DontRequestClientCertificate);
new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestClientCertificateAndVerify);
new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireClientCertificateButDontVerify);
Assert.Throws(typeof(ArgumentNullException), () => new SslServerCredentials(keyCertPairs, null, SslClientCertificateRequestType.RequestAndRequireClientCertificateAndVerify));
}
private async Task CheckAccepted(bool expectPeerAuthenticated)
{
var call = client.UnaryCallAsync(new SimpleRequest { ResponseSize = 10 });
var response = await call;
Assert.AreEqual(10, response.Payload.Body.Length);
Assert.AreEqual(expectPeerAuthenticated.ToString(), call.GetTrailers().First((entry) => entry.Key == IsPeerAuthenticatedMetadataKey).Value);
}
private void CheckRejected()
{
var ex = Assert.Throws<RpcException>(() => client.UnaryCall(new SimpleRequest { ResponseSize = 10 }));
Assert.AreEqual(StatusCode.Unavailable, ex.Status.StatusCode);
}
private async Task CheckAuthContextIsPopulated()
{ {
var call = client.StreamingInputCall(); var call = client.StreamingInputCall();
await call.RequestStream.CompleteAsync(); await call.RequestStream.CompleteAsync();
@ -96,6 +214,7 @@ namespace Grpc.IntegrationTesting
{ {
public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context) public override Task<SimpleResponse> UnaryCall(SimpleRequest request, ServerCallContext context)
{ {
context.ResponseTrailers.Add(IsPeerAuthenticatedMetadataKey, context.AuthContext.IsPeerAuthenticated.ToString());
return Task.FromResult(new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) }); return Task.FromResult(new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) });
} }

@ -964,7 +964,7 @@ GPR_EXPORT grpc_server_credentials* GPR_CALLTYPE
grpcsharp_ssl_server_credentials_create( grpcsharp_ssl_server_credentials_create(
const char* pem_root_certs, const char** key_cert_pair_cert_chain_array, 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, const char** key_cert_pair_private_key_array, size_t num_key_cert_pairs,
int force_client_auth) { grpc_ssl_client_certificate_request_type client_request_type) {
size_t i; size_t i;
grpc_server_credentials* creds; grpc_server_credentials* creds;
grpc_ssl_pem_key_cert_pair* key_cert_pairs = grpc_ssl_pem_key_cert_pair* key_cert_pairs =
@ -981,9 +981,7 @@ grpcsharp_ssl_server_credentials_create(
} }
creds = grpc_ssl_server_credentials_create_ex( creds = grpc_ssl_server_credentials_create_ex(
pem_root_certs, key_cert_pairs, num_key_cert_pairs, pem_root_certs, key_cert_pairs, num_key_cert_pairs,
force_client_auth client_request_type,
? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
: GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE,
NULL); NULL);
gpr_free(key_cert_pairs); gpr_free(key_cert_pairs);
return creds; return creds;

@ -73,7 +73,7 @@
'void grpcsharp_redirect_log(GprLogDelegate callback)', 'void grpcsharp_redirect_log(GprLogDelegate callback)',
'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor)', 'CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor)',
'void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails)', 'void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails)',
'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, int forceClientAuth)', 'ServerCredentialsSafeHandle grpcsharp_ssl_server_credentials_create(string pemRootCerts, string[] keyCertPairCertChainArray, string[] keyCertPairPrivateKeyArray, UIntPtr numKeyCertPairs, SslClientCertificateRequestType clientCertificateRequest)',
'void grpcsharp_server_credentials_release(IntPtr credentials)', 'void grpcsharp_server_credentials_release(IntPtr credentials)',
'ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args)', 'ServerSafeHandle grpcsharp_server_create(ChannelArgsSafeHandle args)',
'void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq)', 'void grpcsharp_server_register_completion_queue(ServerSafeHandle server, CompletionQueueSafeHandle cq)',

Loading…
Cancel
Save