protected ArraySegment<byte> ReadAsymmetricMessage(
ArraySegment<byte> buffer,
X509Certificate2 receiverCertificate,
out uint channelId,
out X509Certificate2 senderCertificate,
out uint requestId,
out uint sequenceNumber)
{
BinaryDecoder decoder = new BinaryDecoder(buffer.Array, buffer.Offset, buffer.Count, Quotas.MessageContext);
string securityPolicyUri = null;
// parse the security header.
ReadAsymmetricMessageHeader(
decoder,
receiverCertificate,
out channelId,
out senderCertificate,
out securityPolicyUri);
// validate the sender certificate.
if (senderCertificate != null && Quotas.CertificateValidator != null && securityPolicyUri != SecurityPolicies.None)
{
Quotas.CertificateValidator.Validate(senderCertificate);
}
// check if this is the first open secure channel request.
if (!m_uninitialized)
{
if (securityPolicyUri != m_securityPolicyUri)
{
throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "Cannot change the security policy after creating the channnel.");
}
}
else
{
// find a matching endpoint description.
if (m_endpoints != null)
{
foreach (EndpointDescription endpoint in m_endpoints)
{
// There may be multiple endpoints with the same securityPolicyUri.
// Just choose the first one that matches. This choice will be re-examined
// When the OpenSecureChannel request body is processed.
if (endpoint.SecurityPolicyUri == securityPolicyUri || (securityPolicyUri == SecurityPolicies.None && endpoint.SecurityMode == MessageSecurityMode.None))
{
m_securityMode = endpoint.SecurityMode;
m_securityPolicyUri = securityPolicyUri;
m_discoveryOnly = false;
m_uninitialized = false;
m_selectedEndpoint = endpoint;
// recalculate the key sizes.
CalculateSymmetricKeySizes();
break;
}
}
}
// allow a discovery only channel with no security if policy not suppported
if (m_uninitialized)
{
if (securityPolicyUri != SecurityPolicies.None)
{
throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "The security policy is not supported.");
}
m_securityMode = MessageSecurityMode.None;
m_securityPolicyUri = SecurityPolicies.None;
m_discoveryOnly = true;
m_uninitialized = false;
m_selectedEndpoint = null;
}
}
int headerSize = decoder.Position;
// decrypt the body.
ArraySegment<byte> plainText = Decrypt(
new ArraySegment<byte>(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize),
new ArraySegment<byte>(buffer.Array, buffer.Offset, headerSize),
receiverCertificate);
// extract signature.
int signatureSize = GetAsymmetricSignatureSize(senderCertificate);
byte[] signature = new byte[signatureSize];
for (int ii = 0; ii < signatureSize; ii++)
{
signature[ii] = plainText.Array[plainText.Offset+plainText.Count-signatureSize+ii];
}
// verify the signature.
ArraySegment<byte> dataToVerify = new ArraySegment<byte>(plainText.Array, plainText.Offset, plainText.Count-signatureSize);
if (!Verify(dataToVerify, signature, senderCertificate))
{
Utils.Trace("Could not verify signature on message.");
throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the signature on the message.");
}
// verify padding.
int paddingCount = 0;
if (SecurityMode != MessageSecurityMode.None)
{
int paddingEnd = -1;
if (receiverCertificate.GetRSAPublicKey().KeySize > TcpMessageLimits.KeySizeExtraPadding)
{
paddingEnd = plainText.Offset + plainText.Count - signatureSize - 1;
paddingCount = plainText.Array[paddingEnd - 1] + plainText.Array[paddingEnd] * 256;
//parse until paddingStart-1; the last one is actually the extrapaddingsize
for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++)
{
if (plainText.Array[ii] != plainText.Array[paddingEnd - 1])
{
throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message.");
}
}
}
else
{
paddingEnd = plainText.Offset + plainText.Count - signatureSize - 1;
paddingCount = plainText.Array[paddingEnd];
for (int ii = paddingEnd - paddingCount; ii < paddingEnd; ii++)
{
if (plainText.Array[ii] != plainText.Array[paddingEnd])
{
throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the padding in the message.");
}
}
}
paddingCount++;
}
// decode message.
decoder = new BinaryDecoder(
plainText.Array,
plainText.Offset + headerSize,
plainText.Count - headerSize,
Quotas.MessageContext);
sequenceNumber = decoder.ReadUInt32(null);
requestId = decoder.ReadUInt32(null);
headerSize += decoder.Position;
decoder.Close();
Utils.Trace("Security Policy: {0}", SecurityPolicyUri);
Utils.Trace("Sender Certificate: {0}", (senderCertificate != null)?senderCertificate.Subject:"(none)");
// return the body.
return new ArraySegment<byte>(
plainText.Array,
plainText.Offset + headerSize,
plainText.Count - headerSize - signatureSize - paddingCount);
}