Pregunta

Necesito proporcionar una comunicación segura entre varios procesos que utilizan sockets TCP/IP para la comunicación.Quiero tanto autenticación como cifrado.En lugar de reinventar la rueda, realmente me gustaría usar SSL y la clase SslStream y certificados autofirmados.Lo que quiero hacer es validar el certificado del proceso remoto con una copia conocida en mi aplicación local.(No es necesario que haya una autoridad de certificación porque tengo la intención de copiar los certificados manualmente).

Para hacer esto, quiero que la aplicación pueda generar automáticamente un nuevo certificado la primera vez que se ejecute.Además de makecert.exe, parece este enlace muestra una manera de generar automáticamente certificados autofirmados, así que eso es un comienzo.

He analizado los métodos AuthenticateAsServer y AuthenticateAsClient de SslStream.Puede proporcionar devoluciones de llamadas para verificación, para que parezca posible.Pero ahora que estoy en detalles, realmente no creo que sea posible hacer esto.

¿Voy en la dirección correcta?¿Hay una mejor alternativa?¿Alguien ha hecho algo como esto antes (básicamente SSL de igual a igual en lugar de cliente-servidor)?

¿Fue útil?

Solución

Paso 1: Generando un certificado autofirmado:

  • descargué el Clase certificado.cs publicado por Doug Cook
  • Utilicé este código para generar un archivo 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);
        }
    

Paso 2: Cargando el certificado

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

Paso 3: Poniendo todo junto

  • lo basé en este ejemplo muy simple de SslStream
  • Recibirá un error en tiempo de compilación sobre la enumeración SslProtocolType.Simplemente cambie eso de SslProtocolType.Default a SslProtocols.Default
  • Hubo 3 advertencias sobre funciones obsoletas.Los reemplacé todos con los reemplazos sugeridos.
  • Reemplacé esta línea en el archivo Server Program.cs con la línea del Paso 2:

    X509Certificado certificado = getServerCert();

  • En el archivo Client Program.cs, asegúrese de configurar serverName = yourhostname.com (y que coincida con el nombre en el certificado)

  • En Client Program.cs, la función CertificateValidationCallback falla porque sslPolicyErrors contiene RemoteCertificateChainErrors.Si profundiza un poco más, esto se debe a que la autoridad emisora ​​que firmó el certificado no es una raíz confiable.
  • No quiero que el usuario importe certificados en el almacén raíz, etc., así que hice un caso especial para esto y verifico que el certificado. GetPublicKeyString() es igual a la clave pública que tengo en el archivo. para ese servidor.Si coincide, devuelvo True desde esa función.Eso parece funcionar.

Etapa 4: Autenticación del cliente

Así es como se autentica mi cliente (es un poco diferente al 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
}

CertificateValidationCallback es el mismo que en el caso del servidor, pero observe cómo AuthenticateAsClient toma una colección de certificados, no solo un certificado.Entonces, debes agregar un LocalCertificateSelectionCallback, como este (en este caso, solo tengo un certificado de cliente, así que solo devuelvo el primero de la colección):

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

Otros consejos

Puede parecer demasiado este ejemplo Muestra Client asíncrono SslStream / implementación del servidor http: // blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

si el certificado no se produce correctamente, puede obtener una excepción El SSL modo de servidor debe utilizar un certificado con la clave privada asociada.

ejemplo básico certificado

makecert -SR LocalMachine -SS Mi -n intercambio -sky CN = Test -sk 123456

o

como archivo externo

makecert -SR LocalMachine -SS Mi -n intercambio -sky CN = Test -sk 123456 c: \ Test.cer

Herramienta de creación de certificados (Makecert.exe)
http://msdn.microsoft.com/en- es / library / bfsktky3% 28VS.80% 29.aspx

Lo que están proponiendo suena bien para mí, excepto que parece que usted está buscando para esperar a que la devolución de llamada se invoca con el fin de generar el certificado. No creo que eso volar; Que yo sepa, usted tiene que proporcionar un certificado válido cuando se invoca AuthenticateAsX.

Sin embargo, estas clases son reemplazable; así que en teoría, se podría crear una clase derivada, que comprueba en primer lugar si un certificado necesita ser generada, lo genera si es necesario, a continuación, invoca el método AuthenticateAsX padres.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top