1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections.Generic;
7 using System.Net.Security;
8 using System.Runtime.InteropServices;
9 using System.Text;
10 using Microsoft.Win32.SafeHandles;
11 
12 internal static partial class Interop
13 {
14     internal static partial class Ssl
15     {
AppVerifyCallback(IntPtr storeCtx, IntPtr arg)16         internal delegate int AppVerifyCallback(IntPtr storeCtx, IntPtr arg);
ClientCertCallback(IntPtr ssl, out IntPtr x509, out IntPtr pkey)17         internal delegate int ClientCertCallback(IntPtr ssl, out IntPtr x509, out IntPtr pkey);
SslCtxSetAlpnCallback(IntPtr ssl, out byte* outp, out byte outlen, byte* inp, uint inlen, IntPtr arg)18         internal unsafe delegate int SslCtxSetAlpnCallback(IntPtr ssl, out byte* outp, out byte outlen, byte* inp, uint inlen, IntPtr arg);
19 
20         [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxCreate")]
SslCtxCreate(IntPtr method)21         internal static extern SafeSslContextHandle SslCtxCreate(IntPtr method);
22 
23         [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxDestroy")]
SslCtxDestroy(IntPtr ctx)24         internal static extern void SslCtxDestroy(IntPtr ctx);
25 
26         [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetCertVerifyCallback")]
SslCtxSetCertVerifyCallback(IntPtr ctx, AppVerifyCallback cb, IntPtr arg)27         internal static extern void SslCtxSetCertVerifyCallback(IntPtr ctx, AppVerifyCallback cb, IntPtr arg);
28 
29         [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetClientCertCallback")]
SslCtxSetClientCertCallback(IntPtr ctx, ClientCertCallback callback)30         internal static extern void SslCtxSetClientCertCallback(IntPtr ctx, ClientCertCallback callback);
31 
32         [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAlpnProtos")]
SslCtxSetAlpnProtos(SafeSslContextHandle ctx, IntPtr protos, int len)33         internal static extern int SslCtxSetAlpnProtos(SafeSslContextHandle ctx, IntPtr protos, int len);
34 
35         [DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_SslCtxSetAlpnSelectCb")]
SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, SslCtxSetAlpnCallback callback, IntPtr arg)36         internal static unsafe extern void SslCtxSetAlpnSelectCb(SafeSslContextHandle ctx, SslCtxSetAlpnCallback callback, IntPtr arg);
37 
SslCtxSetAlpnProtos(SafeSslContextHandle ctx, List<SslApplicationProtocol> protocols)38         internal static unsafe int SslCtxSetAlpnProtos(SafeSslContextHandle ctx, List<SslApplicationProtocol> protocols)
39         {
40             byte[] buffer = ConvertAlpnProtocolListToByteArray(protocols);
41             fixed (byte* b = buffer)
42             {
43                 return SslCtxSetAlpnProtos(ctx, (IntPtr)b, buffer.Length);
44             }
45         }
46 
ConvertAlpnProtocolListToByteArray(List<SslApplicationProtocol> applicationProtocols)47         internal static byte[] ConvertAlpnProtocolListToByteArray(List<SslApplicationProtocol> applicationProtocols)
48         {
49             int protocolSize = 0;
50             foreach (SslApplicationProtocol protocol in applicationProtocols)
51             {
52                 if (protocol.Protocol.Length == 0 || protocol.Protocol.Length > byte.MaxValue)
53                 {
54                     throw new ArgumentException(SR.net_ssl_app_protocols_invalid, nameof(applicationProtocols));
55                 }
56 
57                 protocolSize += protocol.Protocol.Length + 1;
58             }
59 
60             byte[] buffer = new byte[protocolSize];
61             var offset = 0;
62             foreach (SslApplicationProtocol protocol in applicationProtocols)
63             {
64                 buffer[offset++] = (byte)(protocol.Protocol.Length);
65                 protocol.Protocol.Span.CopyTo(new Span<byte>(buffer).Slice(offset));
66                 offset += protocol.Protocol.Length;
67             }
68 
69             return buffer;
70         }
71     }
72 }
73 
74 namespace Microsoft.Win32.SafeHandles
75 {
76     internal sealed class SafeSslContextHandle : SafeHandle
77     {
SafeSslContextHandle()78         private SafeSslContextHandle()
79             : base(IntPtr.Zero, true)
80         {
81         }
82 
SafeSslContextHandle(IntPtr handle, bool ownsHandle)83         internal SafeSslContextHandle(IntPtr handle, bool ownsHandle)
84             : base(handle, ownsHandle)
85         {
86         }
87 
88         public override bool IsInvalid
89         {
90             get { return handle == IntPtr.Zero; }
91         }
92 
ReleaseHandle()93         protected override bool ReleaseHandle()
94         {
95             Interop.Ssl.SslCtxDestroy(handle);
96             SetHandle(IntPtr.Zero);
97             return true;
98         }
99     }
100 }
101