Question

Je dois fournir une communication sécurisée entre les différents processus qui utilisent des sockets TCP / IP pour la communication. Je veux l'authentification et le chiffrement. Plutôt que de réinventer la roue, je voudrais vraiment utiliser SSL et la classe SslStream et certificats auto-signés. Ce que je veux faire est de valider le certificat du processus à distance contre une copie connue dans ma demande locale. (Il n'a pas besoin d'être une autorité de certification parce que je compte pour les certificats à copier manuellement autour).

Pour ce faire, je veux que l'application soit en mesure de générer automatiquement un nouveau certifiate la première fois qu'il est exécuté. En plus de MakeCert.exe, il ressemble à ce lien montre un moyen de générer automatiquement des certificats auto-signés, de sorte que c'est un début.

Je l'ai regardé les méthodes AuthenticateAsServer et AuthenticateAsClient de SslStream. Vous pouvez fournir des rappels pour la vérification, il semble que cela est possible. Mais maintenant que je suis dans les détails, je ne pense pas qu'il soit possible de le faire.

Vais-je dans la bonne direction? Y at-il une meilleure alternative? Quelqu'un at-il fait quelque chose comme ça avant (essentiellement SSL peer-to-peer plutôt que client-serveur)?

Était-ce utile?

La solution

Étape 1: Création d'un certificat auto-signé:

  • J'ai téléchargé le class Certificate.cs posté par Doug Cook,
  • J'ai utilisé ce code pour générer un fichier de certificat .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);
        }
    

Étape 2: Chargement du certificat

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

Étape 3: Mettre ensemble

  • Je me suis basé sur ce très simple exemple de SslStream
  • Vous obtiendrez une erreur de compilation sur l'énumération SslProtocolType. Il suffit de changer que de SslProtocolType.Default à SslProtocols.Default
  • Il y avait 3 avertissements sur les fonctions dépréciées. Je les ai remplacé tous les remplacements proposés.
  • Je l'ai remplacé cette ligne dans le serveur de fichiers Program.cs avec la ligne de l'étape 2:

    X509Certificate cert = getServerCert ();

  • Dans le fichier Program.cs client, assurez-vous que vous définissez serverName = yourhostname.com (et qu'il correspond au nom dans le certificat)

  • Dans la fonction client Program.cs, le CertificateValidationCallback échoue parce que sslPolicyErrors contient un RemoteCertificateChainErrors. Si vous creusez un peu plus profond, cela est parce que l'autorité d'émission qui a signé le certificat n'est pas une racine de confiance.
  • Je n `veux entrer dans ayant les certificats d'importation utilisateur dans le magasin racine, etc., donc je fait un cas particulier pour cela, et je vérifie que certificate.GetPublicKeyString () est égale à la clé publique que je avoir sur fichier pour ce serveur. Si elle correspond, je retourne vrai de cette fonction. Cela semble fonctionner.

Étape 4: Authentification Client

Voici comment mon client authentifie (c'est un peu différent de celui du serveur):

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
}

Le CertificateValidationCallback est le même que dans le cas du serveur, mais notez comment AuthenticateAsClient prend une collection de certificats, non seulement un certificat. Donc, vous devez ajouter un LocalCertificateSelectionCallback, comme celui-ci (dans ce cas, je ne dispose que d'un client cert donc je reviens juste le premier dans la collection):

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

Autres conseils

vous pouvez regarder aussi cet exemple Client / Mise en œuvre du serveur Exemple Asynchronous SslStream http: // blogs.msdn.com/joncole/archive/2007/06/13/sample-asynchronous-sslstream-client-server-implementation.aspx

si le certificat ne se produit pas correctement, vous pouvez obtenir exception Le mode serveur SSL doit utiliser un certificat avec la clé privée associée.

Exemple de certificat de base

makecert -SR LocalMachine -ss Mon -n CN = Test échange -sky -sk 123456

ou

comme fichier externe

makecert -SR LocalMachine -ss Mon échange -n CN = Test -sky -sk 123456 c: \ Test.cer

Certificat outil de création (Makecert.exe)
http://msdn.microsoft.com/en- nous / bibliothèque / bfsktky3% 28VS.80% 29.aspx

Qu'est-ce que vous proposez sonne bien pour moi, sauf que ça sonne comme vous êtes à la recherche d'attendre jusqu'à ce que le rappel est invoqué afin de générer le certificat. Je ne pense pas que cela va voler; Autant que je sache, vous devez fournir un certificat valide lorsque vous invoquez AuthenticateAsX.

Cependant, ces classes sont Overridable; donc en théorie, vous pouvez créer une classe dérivée qui vérifie d'abord si un certificat doit être généré, génère si besoin, puis appelle la méthode AuthenticateAsX mère.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top