protected SslHandshakeStatus ProcessCertificateRequest(HandshakeMessage message)
{
if (m_State == HandshakeType.ServerKeyExchange) {
CipherDefinition cd = CipherSuites.GetCipherDefinition(m_EncryptionScheme);
if (this.m_RemoteCertificate.GetPublicKeyLength() <= 512 || !cd.Exportable)
throw new SslException(AlertDescription.HandshakeFailure, "Invalid message.");
} else if (m_State != HandshakeType.Certificate) {
throw new SslException(AlertDescription.UnexpectedMessage, "CertificateRequest message must be preceded by a Certificate or ServerKeyExchange message.");
}
UpdateHashes(message, HashUpdate.All); // input message
// get supported certificate types
bool supportsRsaCerts = false;
byte[] certTypes = new byte[message.fragment[0]]; // currently we're not doing anything with the supported certificate types
Buffer.BlockCopy(message.fragment, 1, certTypes, 0, certTypes.Length);
for(int i = 0; i < certTypes.Length; i++) {
if (certTypes[i] == 1) { // rsa_sign
supportsRsaCerts = true;
break;
}
}
// get list of distinguished names
if (m_Options.RequestHandler != null && supportsRsaCerts) { // make sure the client passed a delegate
Queue q = new Queue();
DistinguishedNameList r = new DistinguishedNameList();
int size, offset = message.fragment[0] + 3;
byte[] buffer;
while(offset < message.fragment.Length) {
size = message.fragment[offset] * 256 + message.fragment[offset + 1];
buffer = new byte[size];
Buffer.BlockCopy(message.fragment, offset + 2, buffer, 0, size);
q.Enqueue(buffer);
offset += size + 2;
}
// decode RDN structures
while(q.Count > 0) {
r.Add(ProcessName((byte[])q.Dequeue()));
}
RequestEventArgs e = new RequestEventArgs();
try {
m_Options.RequestHandler(Parent, r, e);
if (e.Certificate != null)
m_Options.Certificate = e.Certificate;
} catch (Exception de) {
throw new SslException(de, AlertDescription.InternalError, "The code in the CertRequestEventHandler delegate threw an error.");
}
}
if (!supportsRsaCerts)
m_Options.Certificate = null; // do not send client certificate
m_MutualAuthentication = true;
return new SslHandshakeStatus(SslStatus.MessageIncomplete, null);
}