Использование сертификата X509 с файлом и ключом в C#
Я дал сертификат и пароль на сервер, который принимает SSL-соединение. Я пытался установить соединение с этим сервером, но аутентификация не удалась, в основном потому, что я не знаю, как использовать этот файл и пароль, которые мне дали.
Вот мой код:
X509Certificate certificate = new X509Certificate(
@"c:\mySrvKeystore", KEY_PASSWORD);
public static bool ValidateCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors errors)
{
if (errors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", errors);
return false;
}
public void RunClient(string address, int port)
{
Console.WriteLine("Starting client...");
var client = new TcpClient(address, port);
Console.WriteLine("Client connected.");
var stream = new SslStream(client.GetStream(),false,
ValidateCertificate, null);
try
{
stream.AuthenticateAsClient(address);
Console.WriteLine(stream.IsAuthenticated ? "Client authenticated." : "Client is not authenticated.");
//TODO constantly read from server!
}
catch (AuthenticationException ae)
{
Console.WriteLine("Exception occured: {0}", ae.Message);
if (ae.InnerException != null)
{
Console.WriteLine("Inner exception: {0}", ae.InnerException.Message);
}
Console.WriteLine("Failed to authenticate! closing the client...");
client.Close();
return;
}
catch (Exception ex)
{
Console.WriteLine("General exception occured {0}", ex.Message);
client.Close();
return;
}
}
Итак, как вы можете видеть, в моем коде нет кода, который каким-то образом сообщает серверу (TcpClient или SSLStream), что у меня есть этот файл и ключ!
У меня есть javacode, который без проблем подключается к серверу, но мне пока не удалось преобразовать его в C#. Любая помощь будет отличной!
String keyPassword = "123456";
// String keyPassword = "importkey";
try {
KeyManagerFactory keyManagerFactory;
keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyInput = new FileInputStream("c:\\mySrvKeystore");
keyStore.load(keyInput, keyPassword.toCharArray());
keyInput.close();
keyManagerFactory.init(keyStore, keyPassword.toCharArray());
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new java.security.SecureRandom());
SSLSocketFactory sslsocketfactory = sc.getSocketFactory();
this.sslsocket = (SSLSocket) sslsocketfactory.createSocket(host, port);
} catch (java.security.NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (java.security.KeyManagementException e) {
e.printStackTrace();
} catch (java.security.KeyStoreException e) {
e.printStackTrace();
} catch (java.security.cert.CertificateException e) {
e.printStackTrace();
} catch (java.security.UnrecoverableKeyException e) {
e.printStackTrace();
} finally {}
}
public void run() {
try {
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
OutputStream outputstream = System.out;
OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter);
//get text from server and stuff...no deal!
ОБНОВИТЬ
После преобразования ключа в p12 в соответствии с gtrig проблема теперь заключается в IOException в AutheneticateAsClient
метод здесь:
try
{
var certificate = new X509Certificate2(@"d:\mySrvKeystore.p12", "123456");
X509Certificate2[] X509Certificates = {certificate};
var certsCollection = new X509CertificateCollection(X509Certificates);
//IO EXCEPTION HERE-->
stream.AuthenticateAsClient(address, certsCollection, SslProtocols.Ssl2, false);
Console.WriteLine(stream.IsAuthenticated ? "Client authenticated." : "Client is not authenticated.");
//TODO constantly read from server!
}
Также, когда я использую SSlProtocols.Default
ошибка: RemoteCertificateNameMismatch, RemoteCertificateChainErrors
2 ответа
Вы должны использовать AuthenticateAsClient со списком сертификатов:
X509Certificate[] X509Certificates = { certificate };
X509CertificateCollection certsCollection = new X509CertificateCollection(X509Certificates);
sslStream.AuthenticateAsClient(address, certsCollection, SslProtocols.Default, false);
Чтобы избежать ошибочных сертификатов: измените
public static bool ValidateCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors errors)
{
if (errors == SslPolicyErrors.None)
return true;
if (certificate != null)
{
string SendingCertificateName = "";
//List<string> Subject = CommaText(certificate.Subject); // decode commalist
// SendingCertificateName = ExtractNameValue(Subject, "CN"); // get the CN= value
report = string.Format(CultureInfo.InvariantCulture, "certificatename : {0}, SerialNumber: {1}, {2}, {3}", certificate.Subject, certificate.GetSerialNumberString(), SendingCertificateName, ServerName);
Console.WriteLine(report);
}
Console.WriteLine("Certificate error: {0}", errors);
int allow = AllowPolicyErrors << 1; // AllowPolicyErrors property allowing you to pass certain errors
return (allow & (int)sslPolicyErrors) == (int)sslPolicyErrors; // or just True if you dont't mind.
}
Этот ответ, возможно, не поможет вам пройти весь путь, но он должен приблизить вас.
Вам был предоставлен Java KeyStore (JKS), содержащий закрытый ключ и соответствующий сертификат. Пароль для открытия JKS в соответствии с вашим кодом "123456".
Поскольку JKS содержит закрытый ключ, и, глядя на ваш Java-код, я понимаю, что вам нужно двустороннее (взаимное) SSL-соединение. Это в основном означает, что вы как клиент аутентифицируете сервер, а сервер аутентифицирует вас. Этот файл JKS является вашими учетными данными для использования сервера.
Так как вы используете это в C#? Сначала давайте преобразуем JKS в хранилище ключей PKCS12 с помощью этой команды:
keytool -importkeystore -srckeystore mySrvKeystore -destkeystore mySrvKeystore.p12 -srcstoretype JKS -deststoretype PKCS12
Теперь вы можете импортировать файл PKCS12 в хранилище ключей Windows, что должно сделать его легко доступным из C#. ИЛИ, вы можете импортировать его в объект X509Certificate2 с помощью этого кода:
X509Certificate2 cert = X509Certificate2("C:\Path\mySrvKeystore.p12", "123456");
Теперь вы можете использовать хранилище ключей Windows или объект X509Certificate2 в C# для установления соединения SSL.