Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[System]: Epic: Client Certificate Support - Part Two. #8758

Merged
merged 3 commits into from
May 25, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ MONO_VERSION_BUILD=`echo $VERSION | cut -d . -f 3`
# This can be reset to 0 when Mono's version number is bumped
# since it's part of the corlib version (the prefix '1' in the full
# version number is to ensure the number isn't treated as octal in C)
MONO_CORLIB_COUNTER=6
MONO_CORLIB_COUNTER=7
MONO_CORLIB_VERSION=`printf "1%02d%02d%02d%03d" $MONO_VERSION_MAJOR $MONO_VERSION_MINOR 0 $MONO_CORLIB_COUNTER`

AC_DEFINE_UNQUOTED(MONO_CORLIB_VERSION,$MONO_CORLIB_VERSION,[Version of the corlib-runtime interface])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ public interface IMonoSslStream : IDisposable


MonoTlsConnectionInfo GetConnectionInfo ();

bool CanRenegotiate {
get;
}

Task RenegotiateAsync (CancellationToken cancellationToken);
}

interface IMonoSslStream2 : IMonoSslStream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,10 @@ public static IMonoSslStream GetMonoSslStream (HttpListenerContext context)
*
* - 1: everything up until May 2018
* - 2: the new ServicePointScheduler changes have landed
* - 3: full support for Client Certificates
*
*/
internal const int InternalVersion = 2;
internal const int InternalVersion = 3;

#endregion
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ public sealed class MonoTlsSettings
get; set;
}

public bool DisallowUnauthenticatedCertificateRequest {
get; set;
}

/*
* If you set this here, then it will override 'ServicePointManager.SecurityProtocol'.
*/
Expand Down Expand Up @@ -189,6 +193,7 @@ public MonoTlsSettings Clone ()
CertificateValidationTime = other.CertificateValidationTime;
SendCloseNotify = other.SendCloseNotify;
ClientCertificateIssuers = other.ClientCertificateIssuers;
DisallowUnauthenticatedCertificateRequest = other.DisallowUnauthenticatedCertificateRequest;
if (other.TrustAnchors != null)
TrustAnchors = new X509CertificateCollection (other.TrustAnchors);
if (other.CertificateSearchPaths != null) {
Expand Down
54 changes: 49 additions & 5 deletions mcs/class/System/Mono.AppleTls/AppleTlsContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class AppleTlsContext : MobileTlsContext
MonoTlsConnectionInfo connectionInfo;
bool isAuthenticated;
bool handshakeFinished;
// bool renegotiating;
bool renegotiating;
int handshakeStarted;

bool closed;
Expand Down Expand Up @@ -145,6 +145,24 @@ public override void StartHandshake ()

InitializeConnection ();

/*
* SecureTransport is bugged OS X 10.5.8+ - renegotiation after
* calling SetCertificate() will not work.
*
* We also cannot change options after the handshake has started,
* so if you want to request a client certificate, it will happen
* both during the initial handshake and during renegotiation.
*
* You may check 'SslStream.IsAuthenticated' (which will be false
* during the initial handshake) from within your
* 'LocalCertificateSelectionCallback' and return null to have the
* callback invoked again during renegotiation.
*
* However, the first time your selection callback returns a client
* certificate, that certificate will be used for the rest of the
* session.
*/

SetSessionOption (SslSessionOption.BreakOnCertRequested, true);
SetSessionOption (SslSessionOption.BreakOnClientAuth, true);
SetSessionOption (SslSessionOption.BreakOnServerAuth, true);
Expand Down Expand Up @@ -174,7 +192,7 @@ public override void Flush ()

public override bool ProcessHandshake ()
{
if (handshakeFinished)
if (handshakeFinished && !renegotiating)
throw new NotSupportedException ("Handshake already finished.");

while (true) {
Expand All @@ -191,7 +209,9 @@ public override bool ProcessHandshake ()
} else if (status == SslStatus.WouldBlock) {
return false;
} else if (status == SslStatus.Success) {
Debug ("Handshake complete!");
handshakeFinished = true;
renegotiating = false;
return true;
}
}
Expand Down Expand Up @@ -320,6 +340,9 @@ void InitializeConnection ()
!IPAddress.TryParse (TargetHost, out address)) {
PeerDomainName = ServerName;
}

if (Options.AllowRenegotiation)
SetSessionOption (SslSessionOption.AllowRenegotiation, true);
}

void InitializeSession ()
Expand Down Expand Up @@ -858,7 +881,19 @@ public override unsafe (int ret, bool wantMore) Read (byte[] buffer, int offset,
return (0, false);
}

CheckStatusAndThrow (status, SslStatus.WouldBlock, SslStatus.ClosedGraceful);
CheckStatusAndThrow (status, SslStatus.WouldBlock, SslStatus.ClosedGraceful,
SslStatus.PeerAuthCompleted, SslStatus.PeerClientCertRequested);

if (status == SslStatus.PeerAuthCompleted) {
Debug ($"Renegotiation complete: {GetSessionState ()}");
EvaluateTrust ();
return (0, true);
} else if (status == SslStatus.PeerClientCertRequested) {
Debug ($"Renegotiation asked for client certificate: {GetSessionState ()}");
ClientCertificateRequested ();
return (0, true);
}

var wantMore = status == SslStatus.WouldBlock;
return ((int)processed, wantMore);
} catch (Exception ex) {
Expand Down Expand Up @@ -890,7 +925,16 @@ public override unsafe (int ret, bool wantMore) Write (byte[] buffer, int offset

Debug ("Write done: {0} {1}", status, processed);

CheckStatusAndThrow (status, SslStatus.WouldBlock);
CheckStatusAndThrow (status, SslStatus.WouldBlock,
SslStatus.PeerAuthCompleted, SslStatus.PeerClientCertRequested);

if (status == SslStatus.PeerAuthCompleted) {
Debug ($"Renegotiation complete: {GetSessionState ()}");
EvaluateTrust ();
} else if (status == SslStatus.PeerClientCertRequested) {
Debug ($"Renegotiation asked for client certificate: {GetSessionState ()}");
ClientCertificateRequested ();
}

var wantMore = status == SslStatus.WouldBlock;
return ((int)processed, wantMore);
Expand Down Expand Up @@ -929,7 +973,7 @@ public override void Renegotiate ()

var status = SSLReHandshake (Handle);
CheckStatusAndThrow (status);
// renegotiating = true;
renegotiating = true;
#endif
}

Expand Down
3 changes: 3 additions & 0 deletions mcs/class/System/Mono.Btls/MonoBtlsContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ public override void StartHandshake ()
} else {
ssl.SetServerName (ServerName);
}

if (Options.AllowRenegotiation)
ssl.SetRenegotiateMode (MonoBtlsSslRenegotiateMode.FREELY);
}

void SetPrivateCertificate (X509CertificateImplBtls privateCert)
Expand Down
14 changes: 13 additions & 1 deletion mcs/class/System/Mono.Net.Security/AsyncProtocolRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public AsyncHandshakeRequest (MobileAuthenticatedStream parent, bool sync)

protected override AsyncOperationStatus Run (AsyncOperationStatus status)
{
return Parent.ProcessHandshake (status);
return Parent.ProcessHandshake (status, false);
}
}

Expand Down Expand Up @@ -390,5 +390,17 @@ protected override AsyncOperationStatus Run (AsyncOperationStatus status)
}
}

class AsyncRenegotiateRequest : AsyncProtocolRequest
{
public AsyncRenegotiateRequest (MobileAuthenticatedStream parent)
: base (parent, false)
{
}

protected override AsyncOperationStatus Run (AsyncOperationStatus status)
{
return Parent.ProcessHandshake (status, true);
}
}
}
#endif