Pergunta

Eu preciso para fornecer comunicação segura entre vários processos que estão usando sockets TCP / IP para a comunicação. Eu quero tanto autenticação e criptografia. Ao invés de re-inventar a roda que eu realmente gostaria de SSL uso ea classe SslStream e certificados auto-assinados. O que eu quero fazer é validar o certificado do processo remoto com uma cópia conhecida no meu aplicativo local. (Há não precisa ser uma autoridade de certificação, porque eu pretendo para os certificados a serem copiados em torno manualmente).

Para fazer isso, eu quero que o aplicativo para ser capaz de gerar automaticamente uma nova certifiate a primeira vez que é executado. Além makecert.exe, parece que esta ligação mostra uma maneira de gerar automaticamente auto-assinado certificados, de modo que é um começo.

Eu olhei os métodos AuthenticateAsServer e AuthenticateAsClient de SslStream. Você pode fornecer call-backs para a verificação, por isso parece que isso é possível. Mas agora que estou em detalhes sobre isso, eu realmente não acho que é possível fazer isso.

Am I indo na direção certa? Existe uma alternativa melhor? Alguém já fez algo assim antes (basicamente peer-to-peer SSL em vez de cliente-servidor)?

Foi útil?

Solução

Passo 1: gerar um certificado auto-assinado:

  • Eu baixei o classe Certificate.cs postado por Doug Cozinhe
  • Eu usei esse código para gerar um arquivo de certificado .pfx:

    byte[] c = Certificate.CreateSelfSignCertificatePfx(
            "CN=yourhostname.com", //host name
            DateTime.Parse("2000-01-01"), //not valid before
            DateTime.Parse("2010-01-01"), //not valid after
            "mypassword"); //password to encrypt key file
    
        using (BinaryWriter binWriter = new BinaryWriter(
            File.Open(@"testcert.pfx", FileMode.Create)))
        {
            binWriter.Write(c);
        }
    

Passo 2: Carregar o certificado

    X509Certificate cert = new X509Certificate2(
                            @"testcert.pfx", 
                            "mypassword");

Passo 3: Colocá-lo juntos

  • I baseou em este exemplo SslStream muito simples
  • Você receberá um erro de tempo de compilação sobre a enumeração SslProtocolType. Apenas mudar isso a partir SslProtocolType.Default para SslProtocols.Default
  • Houve 3 avisos sobre funções obsoletas. Eu substituí-los todos com as substituições sugeridas.
  • Eu substituí esta linha no arquivo do servidor Program.cs com a linha a partir do Passo 2:

    X509Certificate cert = getServerCert ();

  • No arquivo Cliente Program.cs, certifique-se de definir serverName = yourhostname.com (e que corresponde ao nome no certificado)

  • No Program.cs cliente, a função CertificateValidationCallback falha porque sslPolicyErrors contém uma RemoteCertificateChainErrors. Se você cavar um pouco mais, isso é porque a entidade emissora que assinou o certificado não é uma raiz confiável.
  • Eu não quero entrar em ter os certificados de importação de usuário para o armazenamento de raiz, etc., por isso fiz um caso especial para isso, e eu verificar que certificate.GetPublicKeyString () é igual à chave pública que eu tem em arquivo para esse servidor. Se ele corresponder, eu retornar True daquela função. Que parece funcionar.

Passo 4: Autenticação do cliente

Veja como meus autentica cliente (que é um pouco diferente do servidor):

TcpClient client = new TcpClient();
client.Connect(hostName, port);

SslStream sslStream = new SslStream(client.GetStream(), false,
    new RemoteCertificateValidationCallback(CertificateValidationCallback),
    new LocalCertificateSelectionCallback(CertificateSelectionCallback));

bool authenticationPassed = true;
try
{
    string serverName = System.Environment.MachineName;

    X509Certificate cert = GetServerCert(SERVER_CERT_FILENAME, SERVER_CERT_PASSWORD);
    X509CertificateCollection certs = new X509CertificateCollection();
    certs.Add(cert);

    sslStream.AuthenticateAsClient(
        serverName,
        certs,
        SslProtocols.Default,
        false); // check cert revokation
}
catch (AuthenticationException)
{
    authenticationPassed = false;
}
if (authenticationPassed)
{
    //do stuff
}

O CertificateValidationCallback é o mesmo que no caso do servidor, mas nota como AuthenticateAsClient leva uma coleção de certificados, não apenas um certificado. Então, você tem que adicionar um LocalCertificateSelectionCallback, como este (neste caso, eu só tenho um certificado de cliente, então eu só retornar o primeiro da coleção):

static X509Certificate CertificateSelectionCallback(object sender,
    string targetHost,
    X509CertificateCollection localCertificates,
    X509Certificate remoteCertificate,
    string[] acceptableIssuers)
{
    return localCertificates[0];
}

Outras dicas

Você pode olhar também este exemplo Amostra Asynchronous SslStream Cliente Implementação / Servidor http: // blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

Se certidão não é apresentada corretamente você pode obter exceção O SSL modo servidor deve usar um certificado com a chave privada associada.

exemplo básico certificado

makecert -SR LocalMachine -ss Meu -n CN = teste de câmbio -Sky sk 123456

ou

como arquivo externo

makecert -SR LocalMachine -ss Meu CN = teste de câmbio -Sky -n sk 123456 c: \ Test.cer

Certificate Creation Tool (Makecert.exe)
http://msdn.microsoft.com/en- us / library / bfsktky3% 28VS.80% 29.aspx

O que você está propondo soa bem para mim, exceto que parece que você está olhando para esperar até que o retorno de chamada é invocado para gerar o certificado. Eu não acho que isso vai voar; AFAIK, você tem que fornecer um certificado válido quando você chamar AuthenticateAsX.

No entanto, essas classes são substituível; portanto, em teoria, você poderia criar uma classe derivada que primeiro verifica se um certificado precisa ser gerado, gera-lo se necessário, em seguida, chama o método AuthenticateAsX pai.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top