Ответ 1
Можете ли вы заставить HttpClient доверять только одному сертификату? ... В основном я хочу, чтобы он мог ТОЛЬКО быть моим сервером/сертификатом, с которым разговаривает мой клиент.
Да. Но какой тип сертификата? Сервер или ЦС? Примеры для обоих.
Кроме того, может быть лучше связать открытый ключ, а не сертификат в случае сервера. Это потому, что некоторые организации, такие как Google, поворачивают свои серверные сертификаты каждые 30 дней или около того, пытаясь ограничить CRL небольшими для мобильных клиентов. Тем не менее, организации будут повторно сертифицировать один и тот же открытый ключ.
Вот пример привязки CA от Использовать определенный CA для SSL-соединения. Это не требует размещения сертификата в магазине сертификатов. Вы можете переносить CA в своем приложении.
static bool VerifyServerCertificate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
try
{
String CA_FILE = "ca-cert.der";
X509Certificate2 ca = new X509Certificate2(CA_FILE);
X509Chain chain2 = new X509Chain();
chain2.ChainPolicy.ExtraStore.Add(ca);
// Check all properties (NoFlag is correct)
chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
// This setup does not have revocation information
chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
// Build the chain
chain2.Build(new X509Certificate2(certificate));
// Are there any failures from building the chain?
if (chain2.ChainStatus.Length == 0)
return false;
// If there is a status, verify the status is NoError
bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError;
Debug.Assert(result == true);
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
return false;
}
Я не понял, как использовать эту цепочку (chain2
выше) по умолчанию, так что нет необходимости в обратном вызове. То есть, установите его в ssl-сокет, и соединение будет "просто работать".
И я не понял, как установить его таким образом, чтобы его передавали в обратный вызов. То есть, я должен построить цепочку для каждого вызова обратного вызова, потому что мой chain2
не передается в функции как chain
.
Вот пример привязки сертификата сервера от OWASP Сертификат и открытый ключ. Это не требует размещения сертификата в магазине сертификатов. Вы можете переносить сертификат или публичный ключ в своем приложении.
// Encoded RSAPublicKey
private static String PUB_KEY = "30818902818100C4A06B7B52F8D17DC1CCB47362" +
"C64AB799AAE19E245A7559E9CEEC7D8AA4DF07CB0B21FDFD763C63A313A668FE9D764E" +
"D913C51A676788DB62AF624F422C2F112C1316922AA5D37823CD9F43D1FC54513D14B2" +
"9E36991F08A042C42EAAEEE5FE8E2CB10167174A359CEBF6FACC2C9CA933AD403137EE" +
"2C3F4CBED9460129C72B0203010001";
public static void Main(string[] args)
{
ServicePointManager.ServerCertificateValidationCallback = PinPublicKey;
WebRequest wr = WebRequest.Create("https://encrypted.google.com/");
wr.GetResponse();
}
public static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
if (null == certificate)
return false;
String pk = certificate.GetPublicKeyString();
if (pk.Equals(PUB_KEY))
return true;
// Bad dog
return false;
}