namespace Mono.Security.Protocol.Tls
{
- public class SslServerStream : SslStreamBase
+#if INSIDE_SYSTEM
+ internal
+#else
+ public
+#endif
+ class SslServerStream : SslStreamBase
{
#region Internal Events
#endregion
+ public event CertificateValidationCallback2 ClientCertValidation2;
#region Constructors
public SslServerStream(
{
}
+ public SslServerStream(
+ Stream stream,
+ X509Certificate serverCertificate,
+ bool clientCertificateRequired,
+ bool requestClientCertificate,
+ bool ownsStream)
+ : this (stream, serverCertificate, clientCertificateRequired, requestClientCertificate, ownsStream, SecurityProtocolType.Default)
+ {
+ }
+
public SslServerStream(
Stream stream,
X509Certificate serverCertificate,
bool clientCertificateRequired,
bool ownsStream,
SecurityProtocolType securityProtocolType)
+ : this (stream, serverCertificate, clientCertificateRequired, false, ownsStream, securityProtocolType)
+ {
+ }
+
+ public SslServerStream(
+ Stream stream,
+ X509Certificate serverCertificate,
+ bool clientCertificateRequired,
+ bool requestClientCertificate,
+ bool ownsStream,
+ SecurityProtocolType securityProtocolType)
: base(stream, ownsStream)
{
this.context = new ServerContext(
this,
securityProtocolType,
serverCertificate,
- clientCertificateRequired);
+ clientCertificateRequired,
+ requestClientCertificate);
this.protocol = new ServerRecordProtocol(innerStream, (ServerContext)this.context);
}
Fig. 1 - Message flow for a full handshake
*/
- internal override IAsyncResult OnBeginNegotiateHandshake(AsyncCallback callback, object state)
+ internal override IAsyncResult BeginNegotiateHandshake(AsyncCallback callback, object state)
{
// Reset the context if needed
if (this.context.HandshakeState != HandshakeState.None)
}
- internal override void OnNegotiateHandshakeCallback(IAsyncResult asyncResult)
+ internal override void EndNegotiateHandshake(IAsyncResult asyncResult)
{
// Receive Client Hello message and ignore it
this.protocol.EndReceiveRecord(asyncResult);
this.protocol.SendRecord(HandshakeType.Certificate);
// If the negotiated cipher is a KeyEx cipher send ServerKeyExchange
- if (this.context.Cipher.ExchangeAlgorithmType == ExchangeAlgorithmType.RsaKeyX)
+ if (this.context.Negotiating.Cipher.IsExportable)
{
this.protocol.SendRecord(HandshakeType.ServerKeyExchange);
}
- bool certRequested = false;
-
// If the negotiated cipher is a KeyEx cipher or
// the client certificate is required send the CertificateRequest message
- if (this.context.Cipher.ExchangeAlgorithmType == ExchangeAlgorithmType.RsaKeyX ||
- ((ServerContext)this.context).ClientCertificateRequired)
+ if (this.context.Negotiating.Cipher.IsExportable ||
+ ((ServerContext)this.context).ClientCertificateRequired ||
+ ((ServerContext)this.context).RequestClientCertificate)
{
this.protocol.SendRecord(HandshakeType.CertificateRequest);
- certRequested = true;
}
// Send ServerHelloDone message
this.protocol.SendRecord(HandshakeType.ServerHelloDone);
// Receive client response, until the Client Finished message
- // is received
+ // is received. IE can be interrupted at this stage and never
+ // complete the handshake
while (this.context.LastHandshakeMsg != HandshakeType.Finished)
{
- this.protocol.ReceiveRecord(this.innerStream);
- }
-
- if (certRequested && (this.context.ClientSettings.ClientCertificate == null))
- {
- // we asked for a certificate but didn't receive one
- // e.g. wget for SSL3
- if (!RaiseClientCertificateValidation(null, new int[0]))
+ byte[] record = this.protocol.ReceiveRecord(this.innerStream);
+ if ((record == null) || (record.Length == 0))
{
throw new TlsException(
- AlertDescription.BadCertificate,
- "No certificate received from client.");
+ AlertDescription.HandshakeFailiure,
+ "The client stopped the handshake.");
}
}
// Send ChangeCipherSpec and ServerFinished messages
this.protocol.SendChangeCipherSpec();
+ this.protocol.SendRecord (HandshakeType.Finished);
// The handshake is finished
this.context.HandshakeState = HandshakeState.Finished;
+ // Reset Handshake messages information
+ this.context.HandshakeMessages.Reset ();
+
// Clear Key Info
this.context.ClearKeyInfo();
}
return (errors != null && errors.Length == 0);
}
+ internal override bool HaveRemoteValidation2Callback {
+ get { return ClientCertValidation2 != null; }
+ }
+
+ internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection)
+ {
+ CertificateValidationCallback2 cb = ClientCertValidation2;
+ if (cb != null)
+ return cb (collection);
+ return null;
+ }
+
internal bool RaiseClientCertificateValidation(
X509Certificate certificate,
int[] certificateErrors)