Просить SslStream принять ТОЛЬКО сертификат, подписанный определенным открытым ключом - PullRequest
2 голосов
/ 08 марта 2011

У меня есть рабочая реализация этого, но я хочу убедиться, что это безопасно.Цель состоит в том, чтобы использовать SSLStream и принимать только SSL-сертификаты с сервера, которые подписаны определенным ключом RSA.

Вот мой код подключения:

        var client = new TcpClient("server_address", port_number);
        var sslStream = new SslStream(client.GetStream(), false,
            new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
        sslStream.AuthenticateAsClient("SpeechGrid");

А вот моя реализацияValidateServerCertificate:

    private static bool ValidateServerCertificate(object sender, X509Certificate certificate,
            X509Chain chain, SslPolicyErrors sslPolicyErrors) {

        // Only accept our specific key pair
        foreach (var cert in chain.ChainElements) {
            if (cert.Certificate.GetPublicKeyString() == k_prodPublicKey) {
                return true;
            }
        }

        return false;
    }

Из-за богатства объекта X509Chain я хочу убедиться, что мне не нужно проверять такие вещи, как X509ChainStatusFlags.NotSignatureValid и т. Д.

Например,Возможно ли, чтобы злоумышленник «потребовал» подписать мой открытый ключ, отправить неверную подпись, и эта атака сработает, потому что .NET предполагает, что я проверяю все эти флаги?

Спасибо!!

ОБНОВЛЕНИЕ: Хорошо, пока я решил поставить следующие проверки над исходным foreach.Обратите внимание, что это отчасти зависит от приложения;например, если бы я хотел, чтобы срок действия сертификатов истек, я бы проверил NotTimeValid и т. д.

        foreach (var status in chain.ChainStatus) {
            switch (status.Status) {
                case X509ChainStatusFlags.Cyclic:
                case X509ChainStatusFlags.NotSignatureValid:
                case X509ChainStatusFlags.PartialChain:
                    return false;
            }
        }

Ответы [ 2 ]

1 голос
/ 09 марта 2011

Я бы изменил логику проверки, которую вы добавили в обновлении на ваш вопрос. Вместо того, чтобы искать что-то не так и принимать все остальное:

foreach (thing that I can think of that might be wrong)
 return false;

if (public key matches regardless of other policy errors)
 return true;

... Вместо этого я бы посмотрел на то, что может быть неправильно, но все же допустимо, и отклонил бы любые другие ошибки политики:

if (policy errors)
{
 foreach (error that is acceptable: remote name mismatch, untrusted root, etc.)
   policy errors -= that particular error
}

if (any policy errors left)
 return false;
else if (public key matches)
 return true;
else
 return false;

Как-то так для первой части (я не тестировал и не компилировал это):

if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) == SslPolicyErrors.RemoteCertificateNameMismatch)
{
    sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch;
}

if ((sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors) == SslPolicyErrors.RemoteCertificateChainErrors)
{
    var otherFlagsFound =
        from i in chain.ChainStatus
        where (i.Status & ~X509ChainStatusFlags.UntrustedRoot) != X509ChainStatusFlags.NoError
        select i;

    if (otherFlagsFound.Count() == 0)
    {
        sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateChainErrors;
    }
}
0 голосов
/ 08 марта 2011

Вы можете проверить параметр sslPolicyErrors на наличие дополнительных ошибок, таких как истек срок действия или если сертификаты не являются доверенными.Если все в порядке, он должен вернуть SslPolicyErrors.None.В вычислительном отношении невозможно получить закрытый ключ из открытого ключа, поэтому вам не нужно беспокоиться о том, что кто-то другой создаст ту же пару ключей и подпишет ее.

...