[SslContext] Subclass NativeObject + numerous other code updates (#13105)

* Subclass NativeObject to reuse object lifetime code.
* Enable nullability and fix code accordingly.
* Use 'is' and 'is not' instead of '==' and '!=' for object identity.
* Use the null-safe NativeObjectExtensions.GetHandle extension method to get
  the handle instead of checking for null (avoids some code duplication).
* Use 'nameof (parameter)' instead of string constants.
This commit is contained in:
Rolf Bjarne Kvinge 2021-10-25 21:14:14 +02:00 коммит произвёл GitHub
Родитель 959c65d06c
Коммит 44f88fcd92
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 46 добавлений и 68 удалений

Просмотреть файл

@ -7,6 +7,8 @@
// Copyright 2014-2016 Xamarin Inc. // Copyright 2014-2016 Xamarin Inc.
// //
#nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
@ -37,60 +39,36 @@ namespace Security {
[Obsolete ("Starting with macos10.15 use 'Network.framework' instead.", DiagnosticId = "BI1234", UrlFormat = "https://github.com/xamarin/xamarin-macios/wiki/Obsolete")] [Obsolete ("Starting with macos10.15 use 'Network.framework' instead.", DiagnosticId = "BI1234", UrlFormat = "https://github.com/xamarin/xamarin-macios/wiki/Obsolete")]
#endif #endif
#endif #endif
public class SslContext : INativeObject, IDisposable { public class SslContext : NativeObject {
SslConnection connection; SslConnection? connection;
SslStatus result; SslStatus result;
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern static /* SSLContextRef */ IntPtr SSLCreateContext (/* CFAllocatorRef */ IntPtr alloc, SslProtocolSide protocolSide, SslConnectionType connectionType); extern static /* SSLContextRef */ IntPtr SSLCreateContext (/* CFAllocatorRef */ IntPtr alloc, SslProtocolSide protocolSide, SslConnectionType connectionType);
public SslContext (SslProtocolSide protocolSide, SslConnectionType connectionType) public SslContext (SslProtocolSide protocolSide, SslConnectionType connectionType)
: base (SSLCreateContext (IntPtr.Zero, protocolSide, connectionType), true)
{ {
Handle = SSLCreateContext (IntPtr.Zero, protocolSide, connectionType);
} }
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern static /* OSStatus */ SslStatus SSLClose (/* SSLContextRef */ IntPtr context); extern static /* OSStatus */ SslStatus SSLClose (/* SSLContextRef */ IntPtr context);
~SslContext () protected override void Dispose (bool disposing)
{ {
Dispose (false);
}
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
bool disposed;
protected virtual void Dispose (bool disposing)
{
if (disposed)
return;
disposed = true;
if (Handle != IntPtr.Zero) if (Handle != IntPtr.Zero)
result = SSLClose (Handle); result = SSLClose (Handle);
// don't remove the read/write delegates before we closed the connection, i.e. // don't remove the read/write delegates before we closed the connection, i.e.
// the SSLClose will send an Alert for a "close notify" // the SSLClose will send an Alert for a "close notify"
if (connection != null) { if (connection is not null) {
connection.Dispose (); connection.Dispose ();
connection = null; connection = null;
} }
// SSLCreateContext -> CFRelease (not SSLDisposeContext) base.Dispose (disposing);
if (Handle != IntPtr.Zero) {
CFObject.CFRelease (Handle);
Handle = IntPtr.Zero;
} }
}
public IntPtr Handle { get; private set; }
public SslStatus GetLastStatus () public SslStatus GetLastStatus ()
{ {
@ -149,11 +127,11 @@ namespace Security {
extern static /* OSStatus */ SslStatus SSLSetConnection (/* SSLContextRef */ IntPtr context, /* SSLConnectionRef */ IntPtr connection); extern static /* OSStatus */ SslStatus SSLSetConnection (/* SSLContextRef */ IntPtr context, /* SSLConnectionRef */ IntPtr connection);
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern static /* OSStatus */ SslStatus SSLSetIOFuncs (/* SSLContextRef */ IntPtr context, /* SSLReadFunc */ SslReadFunc readFunc, /* SSLWriteFunc */ SslWriteFunc writeFunc); extern static /* OSStatus */ SslStatus SSLSetIOFuncs (/* SSLContextRef */ IntPtr context, /* SSLReadFunc */ SslReadFunc? readFunc, /* SSLWriteFunc */ SslWriteFunc? writeFunc);
public SslConnection Connection { public SslConnection? Connection {
get { get {
if (connection == null) if (connection is null)
return null; return null;
IntPtr value; IntPtr value;
result = SSLGetConnection (Handle, out value); result = SSLGetConnection (Handle, out value);
@ -162,14 +140,14 @@ namespace Security {
return connection; return connection;
} }
set { set {
// the read/write delegates needs to be set before set set the connection id // the read/write delegates needs to be set before setting the connection id
if (value == null) if (value is null)
result = SSLSetIOFuncs (Handle, null, null); result = SSLSetIOFuncs (Handle, null, null);
else else
result = SSLSetIOFuncs (Handle, value.ReadFunc, value.WriteFunc); result = SSLSetIOFuncs (Handle, value.ReadFunc, value.WriteFunc);
if (result == SslStatus.Success) { if (result == SslStatus.Success) {
result = SSLSetConnection (Handle, value == null ? IntPtr.Zero : value.ConnectionId); result = SSLSetConnection (Handle, value is null ? IntPtr.Zero : value.ConnectionId);
connection = value; connection = value;
} }
} }
@ -228,7 +206,7 @@ namespace Security {
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLSetPeerID (/* SSLContextRef */ IntPtr context, /* const void* */ byte* peerID, /* size_t */ nint peerIDLen); extern unsafe static /* OSStatus */ SslStatus SSLSetPeerID (/* SSLContextRef */ IntPtr context, /* const void* */ byte* peerID, /* size_t */ nint peerIDLen);
public unsafe byte[] PeerId { public unsafe byte[]? PeerId {
get { get {
nint length; nint length;
IntPtr id; IntPtr id;
@ -240,7 +218,7 @@ namespace Security {
return data; return data;
} }
set { set {
nint length = (value == null) ? 0 : value.Length; nint length = (value is null) ? 0 : value.Length;
fixed (byte *p = value) { fixed (byte *p = value) {
result = SSLSetPeerID (Handle, p, length); result = SSLSetPeerID (Handle, p, length);
} }
@ -263,8 +241,8 @@ namespace Security {
internal unsafe SslStatus Read (byte[] data, int offset, int size, out nint processed) internal unsafe SslStatus Read (byte[] data, int offset, int size, out nint processed)
{ {
if (data == null) if (data is null)
throw new ArgumentNullException ("data"); throw new ArgumentNullException (nameof (data));
fixed (byte *d = &data [offset]) fixed (byte *d = &data [offset])
result = SSLRead (Handle, d, size, out processed); result = SSLRead (Handle, d, size, out processed);
return result; return result;
@ -272,7 +250,7 @@ namespace Security {
public unsafe SslStatus Read (byte[] data, out nint processed) public unsafe SslStatus Read (byte[] data, out nint processed)
{ {
int size = data == null ? 0 : data.Length; int size = data is null ? 0 : data.Length;
fixed (byte *d = data) fixed (byte *d = data)
result = SSLRead (Handle, d, size, out processed); result = SSLRead (Handle, d, size, out processed);
return result; return result;
@ -283,8 +261,8 @@ namespace Security {
internal unsafe SslStatus Write (byte[] data, int offset, int size, out nint processed) internal unsafe SslStatus Write (byte[] data, int offset, int size, out nint processed)
{ {
if (data == null) if (data is null)
throw new ArgumentNullException ("data"); throw new ArgumentNullException (nameof (data));
fixed (byte *d = &data [offset]) fixed (byte *d = &data [offset])
result = SSLWrite (Handle, d, size, out processed); result = SSLWrite (Handle, d, size, out processed);
return result; return result;
@ -292,7 +270,7 @@ namespace Security {
public unsafe SslStatus Write (byte[] data, out nint processed) public unsafe SslStatus Write (byte[] data, out nint processed)
{ {
int size = data == null ? 0 : data.Length; int size = data is null ? 0 : data.Length;
fixed (byte *d = data) fixed (byte *d = data)
result = SSLWrite (Handle, d, size, out processed); result = SSLWrite (Handle, d, size, out processed);
return result; return result;
@ -305,7 +283,7 @@ namespace Security {
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLGetSupportedCiphers (/* SSLContextRef */ IntPtr context, SslCipherSuite *ciphers, /* size_t* */ ref nint numCiphers); extern unsafe static /* OSStatus */ SslStatus SSLGetSupportedCiphers (/* SSLContextRef */ IntPtr context, SslCipherSuite *ciphers, /* size_t* */ ref nint numCiphers);
public unsafe IList<SslCipherSuite> GetSupportedCiphers () public unsafe IList<SslCipherSuite>? GetSupportedCiphers ()
{ {
nint n; nint n;
result = SSLGetNumberSupportedCiphers (Handle, out n); result = SSLGetNumberSupportedCiphers (Handle, out n);
@ -327,7 +305,7 @@ namespace Security {
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLGetEnabledCiphers (/* SSLContextRef */ IntPtr context, SslCipherSuite *ciphers, /* size_t* */ ref nint numCiphers); extern unsafe static /* OSStatus */ SslStatus SSLGetEnabledCiphers (/* SSLContextRef */ IntPtr context, SslCipherSuite *ciphers, /* size_t* */ ref nint numCiphers);
public unsafe IList<SslCipherSuite> GetEnabledCiphers () public unsafe IList<SslCipherSuite>? GetEnabledCiphers ()
{ {
nint n; nint n;
result = SSLGetNumberEnabledCiphers (Handle, out n); result = SSLGetNumberEnabledCiphers (Handle, out n);
@ -348,8 +326,8 @@ namespace Security {
public unsafe SslStatus SetEnabledCiphers (IEnumerable<SslCipherSuite> ciphers) public unsafe SslStatus SetEnabledCiphers (IEnumerable<SslCipherSuite> ciphers)
{ {
if (ciphers == null) if (ciphers is null)
throw new ArgumentNullException ("ciphers"); throw new ArgumentNullException (nameof (ciphers));
var array = ciphers.ToArray (); var array = ciphers.ToArray ();
fixed (SslCipherSuite *p = array) fixed (SslCipherSuite *p = array)
@ -401,7 +379,7 @@ namespace Security {
public unsafe SslStatus SetDatagramHelloCookie (byte[] cookie) public unsafe SslStatus SetDatagramHelloCookie (byte[] cookie)
{ {
nint len = cookie == null ? 0 : cookie.Length; nint len = cookie is null ? 0 : cookie.Length;
fixed (byte *p = cookie) fixed (byte *p = cookie)
result = SSLSetDatagramHelloCookie (Handle, p, len); result = SSLSetDatagramHelloCookie (Handle, p, len);
return result; return result;
@ -411,10 +389,10 @@ namespace Security {
extern unsafe static /* OSStatus */ SslStatus SSLGetPeerDomainNameLength (/* SSLContextRef */ IntPtr context, /* size_t* */ out nint peerNameLen); extern unsafe static /* OSStatus */ SslStatus SSLGetPeerDomainNameLength (/* SSLContextRef */ IntPtr context, /* size_t* */ out nint peerNameLen);
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLGetPeerDomainName (/* SSLContextRef */ IntPtr context, /* char* */ byte[] peerName, /* size_t */ ref nint peerNameLen); extern unsafe static /* OSStatus */ SslStatus SSLGetPeerDomainName (/* SSLContextRef */ IntPtr context, /* char* */ byte[]? peerName, /* size_t */ ref nint peerNameLen);
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLSetPeerDomainName (/* SSLContextRef */ IntPtr context, /* char* */ byte[] peerName, /* size_t */ nint peerNameLen); extern unsafe static /* OSStatus */ SslStatus SSLSetPeerDomainName (/* SSLContextRef */ IntPtr context, /* char* */ byte[]? peerName, /* size_t */ nint peerNameLen);
public string PeerDomainName { public string PeerDomainName {
get { get {
@ -427,7 +405,7 @@ namespace Security {
return result == SslStatus.Success ? Encoding.UTF8.GetString (bytes) : String.Empty; return result == SslStatus.Success ? Encoding.UTF8.GetString (bytes) : String.Empty;
} }
set { set {
if (value == null) { if (value is null) {
result = SSLSetPeerDomainName (Handle, null, 0); result = SSLSetPeerDomainName (Handle, null, 0);
} else { } else {
var bytes = Encoding.UTF8.GetBytes (value); var bytes = Encoding.UTF8.GetBytes (value);
@ -443,7 +421,7 @@ namespace Security {
extern unsafe static /* OSStatus */ SslStatus SSLCopyDistinguishedNames (/* SSLContextRef */ IntPtr context, /* CFArrayRef* */ out IntPtr names); extern unsafe static /* OSStatus */ SslStatus SSLCopyDistinguishedNames (/* SSLContextRef */ IntPtr context, /* CFArrayRef* */ out IntPtr names);
// TODO: need to setup a server that requires client-side certificates // TODO: need to setup a server that requires client-side certificates
public IList<T> GetDistinguishedNames<T> () public IList<T>? GetDistinguishedNames<T> ()
{ {
IntPtr p; IntPtr p;
result = SSLCopyDistinguishedNames (Handle, out p); result = SSLCopyDistinguishedNames (Handle, out p);
@ -480,15 +458,17 @@ namespace Security {
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLSetCertificate (/* SSLContextRef */ IntPtr context, /* _Nullable CFArrayRef */ IntPtr certRefs); extern unsafe static /* OSStatus */ SslStatus SSLSetCertificate (/* SSLContextRef */ IntPtr context, /* _Nullable CFArrayRef */ IntPtr certRefs);
NSArray Bundle (SecIdentity identity, IEnumerable<SecCertificate> certificates) NSArray Bundle (SecIdentity? identity, IEnumerable<SecCertificate>? certificates)
{ {
int i = identity == null ? 0 : 1; int i = identity is null ? 0 : 1;
int n = certificates == null ? 0 : certificates.Count (); int n = certificates is null ? 0 : certificates.Count ();
var ptrs = new IntPtr [n + i]; var ptrs = new IntPtr [n + i];
if (i == 1) if (i == 1)
ptrs [0] = identity.Handle; ptrs [0] = identity!.Handle;
if (certificates is not null) {
foreach (var certificate in certificates) foreach (var certificate in certificates)
ptrs [i++] = certificate.Handle; ptrs [i++] = certificate.Handle;
}
return NSArray.FromIntPtrs (ptrs); return NSArray.FromIntPtrs (ptrs);
} }
@ -549,7 +529,7 @@ namespace Security {
[DllImport (Constants.SecurityLibrary)] [DllImport (Constants.SecurityLibrary)]
extern unsafe static /* OSStatus */ SslStatus SSLCopyPeerTrust (/* SSLContextRef */ IntPtr context, /* SecTrustRef */ out IntPtr trust); extern unsafe static /* OSStatus */ SslStatus SSLCopyPeerTrust (/* SSLContextRef */ IntPtr context, /* SecTrustRef */ out IntPtr trust);
public SecTrust PeerTrust { public SecTrust? PeerTrust {
get { get {
IntPtr value; IntPtr value;
result = SSLCopyPeerTrust (Handle, out value); result = SSLCopyPeerTrust (Handle, out value);
@ -605,7 +585,7 @@ namespace Security {
[EditorBrowsable (EditorBrowsableState.Advanced)] [EditorBrowsable (EditorBrowsableState.Advanced)]
public int SetSessionConfig (NSString config) public int SetSessionConfig (NSString config)
{ {
if (config == null) if (config is null)
throw new ArgumentNullException (nameof (config)); throw new ArgumentNullException (nameof (config));
return SSLSetSessionConfig (Handle, config.Handle); return SSLSetSessionConfig (Handle, config.Handle);
@ -617,7 +597,7 @@ namespace Security {
#endif #endif
public int SetSessionConfig (SslSessionConfig config) public int SetSessionConfig (SslSessionConfig config)
{ {
return SetSessionConfig (config.GetConstant ()); return SetSessionConfig (config.GetConstant ()!);
} }
#if !NET #if !NET
@ -722,7 +702,7 @@ namespace Security {
#endif #endif
public int SetOcspResponse (NSData response) public int SetOcspResponse (NSData response)
{ {
if (response == null) if (response is null)
throw new ArgumentNullException (nameof (response)); throw new ArgumentNullException (nameof (response));
return SSLSetOCSPResponse (Handle, response.Handle); return SSLSetOCSPResponse (Handle, response.Handle);
} }
@ -768,15 +748,13 @@ namespace Security {
[SupportedOSPlatform ("tvos11.0")] [SupportedOSPlatform ("tvos11.0")]
#endif #endif
public string[] GetAlpnProtocols (out int error) public string?[] GetAlpnProtocols (out int error)
{ {
IntPtr protocols = IntPtr.Zero; // must be null, CFArray allocated by SSLCopyALPNProtocols IntPtr protocols = IntPtr.Zero; // must be null, CFArray allocated by SSLCopyALPNProtocols
error = SSLCopyALPNProtocols (Handle, ref protocols); error = SSLCopyALPNProtocols (Handle, ref protocols);
if (protocols == IntPtr.Zero) if (protocols == IntPtr.Zero)
return Array.Empty<string> (); return Array.Empty<string> ();
var result = CFArray.StringArrayFromHandle (protocols); return CFArray.StringArrayFromHandle (protocols, true)!;
CFObject.CFRelease (protocols);
return result;
} }
#if !NET #if !NET
@ -786,7 +764,7 @@ namespace Security {
[SupportedOSPlatform ("ios11.0")] [SupportedOSPlatform ("ios11.0")]
[SupportedOSPlatform ("tvos11.0")] [SupportedOSPlatform ("tvos11.0")]
#endif #endif
public string[] GetAlpnProtocols () public string?[] GetAlpnProtocols ()
{ {
int error; int error;
return GetAlpnProtocols (out error); return GetAlpnProtocols (out error);