Comment ajouter SSL à une application .net qui utilise httplistener - elle ne fonctionnera *pas* sur IIS

StackOverflow https://stackoverflow.com/questions/4004

Question

Modifications les plus récentes en grasJ'utilise le .net HttpListener classe, mais je ne fonctionnerai pas sur IIS et je n'utilise pas ASP.net.Ce site web décrit le code à utiliser réellement pour implémenter SSL avec asp.net et ce site décrit comment configurer les certificats (même si je ne sais pas si cela fonctionne uniquement pour IIS ou non).

La documentation de la classe décrit différents types d'authentification (de base, digest, Windows, etc.) --- aucun d'entre eux ne fait référence à SSL.Il est dit que si HTTPS est utilisé, vous devrez définir un certificat de serveur.Est-ce que cela va être un paramètre de propriété sur une seule ligne et HttpListener tu comprends le reste ?

Bref, j'ai besoin de savoir comment mettre en place les certificats et comment modifier le code pour implémenter SSL.

Bien que cela ne se produise pas lorsque j'essaie d'accéder à HTTPS, j'ai remarqué une erreur dans mon journal des événements système : la source est "Schannel" et le contenu du message est :

Une erreur fatale s'est produite lors de la tentative d'accéder à la clé privée d'identification SSL Server.Le code d'erreur renvoyé du module cryptographique est 0x80090016.

Modifier:
Mesures prises jusqu'à présent

  • Création d'un HTTPListener fonctionnel en C# qui fonctionne pour les connexions HTTP (par ex."http://localhost:8089/foldername/"
  • Création d'un certificat à l'aide de makecert.exe
  • Ajout du certificat à approuver à l'aide de certmgr.exe
  • Httpcfg.exe utilisé pour écouter les connexions SSL sur un port de test (par ex.8090)
  • Ajout du port 8080 au HTTPListener via Listener.Prefixes.Add(https://localhost:8090/foldername/");
  • testé une connexion client HTTP, par ex.(http://localhost:8089/foldername/") dans un navigateur et recevez un retour correct
  • testé une connexion client HTTPS, par ex.(http://localhost:8090/foldername/") dans un navigateur et recevez "Transfert de données interrompu" (dans Firefox)
  • le débogage dans Visual Studio montre que le rappel de l'auditeur qui reçoit les requêtes n'est jamais touché lorsque la connexion HTTPS démarre - je ne vois aucun endroit où je pourrais définir un point d'arrêt pour attraper autre chose plus tôt.
  • netstat montre que les ports d'écoute sont ouverts pour HTTPS et HTTP.le port HTTPS va à TIME_WAIT après une tentative de connexion.
  • Violoneux et Analyseur HTTP n'attrapez aucune partie du trafic, je suppose que cela ne va pas assez loin dans le processus pour apparaître dans ces outils d'analyse HTTP

Des questions

  • Quel pourrait être le problème?
  • Y a-t-il un morceau de code .Net qui me manque (ce qui signifie que je dois faire plus en C# que simplement ajouter un préfixe à l'écouteur qui pointe vers HTTPS, ce que j'ai fait)
  • Vous avez manqué une étape de configuration quelque part ?
  • Que puis-je faire d'autre pour analyser le problème ?
  • Le message d'erreur dans le journal des événements système est-il un signe du problème ?Si oui, comment serait-il réparé ?

Pas de solution correcte

Autres conseils

J'ai un problème similaire et il semble qu'il puisse y avoir un problème avec le certificat lui-même.

Voici le chemin qui a fonctionné pour moi :

makecert.exe -r -a sha1 -n CN=localhost -sky exchange -pe -b 01/01/2000 -e 01/01/2050 -ss my -sr localmachine

puis cherche le certificat empreinte, copiez-le dans le presse-papiers et supprimez les espaces.Ce sera un paramètre après -h dans la commande suivante :

HttpCfg.exe set ssl -i 0.0.0.0:801 -h 35c65fd4853f49552471d2226e03dd10b7a11755

puis exécutez un hôte de service sur https://localhost:801/ et ça fonctionne parfaitement.

ce que je ne peux pas faire fonctionner, c'est que https s'exécute sur un certificat auto-généré.Voici le code que j'exécute pour en générer un (gestion des erreurs supprimée pour plus de clarté) :

LPCTSTR pszX500 = subject;
DWORD cbEncoded = 0;
CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &cbEncoded, NULL);
pbEncoded = (BYTE *)malloc(cbEncoded);
CertStrToName(X509_ASN_ENCODING, pszX500, CERT_X500_NAME_STR, NULL, pbEncoded, &cbEncoded, NULL);

// Prepare certificate Subject for self-signed certificate
CERT_NAME_BLOB SubjectIssuerBlob;
memset(&SubjectIssuerBlob, 0, sizeof(SubjectIssuerBlob));
SubjectIssuerBlob.cbData = cbEncoded;
SubjectIssuerBlob.pbData = pbEncoded;

// Prepare key provider structure for self-signed certificate
CRYPT_KEY_PROV_INFO KeyProvInfo;
memset(&KeyProvInfo, 0, sizeof(KeyProvInfo));
KeyProvInfo.pwszContainerName = _T("my-container");
KeyProvInfo.pwszProvName = NULL;
KeyProvInfo.dwProvType = PROV_RSA_FULL;
KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
KeyProvInfo.cProvParam = 0;
KeyProvInfo.rgProvParam = NULL;
KeyProvInfo.dwKeySpec = AT_SIGNATURE;

// Prepare algorithm structure for self-signed certificate
CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
memset(&SignatureAlgorithm, 0, sizeof(SignatureAlgorithm));
SignatureAlgorithm.pszObjId = szOID_RSA_SHA1RSA;

// Prepare Expiration date for self-signed certificate
SYSTEMTIME EndTime;
GetSystemTime(&EndTime);
EndTime.wYear += 5;

// Create self-signed certificate
pCertContext = CertCreateSelfSignCertificate(NULL, &SubjectIssuerBlob, 0, &KeyProvInfo, &SignatureAlgorithm, 0, &EndTime, 0);
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");
CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0);

Le certificat s'affiche correctement et possède une clé privée fonctionnelle, mais https expirera comme si l'empreinte numérique n'avait jamais été enregistrée.Si quelqu'un sait pourquoi, commentez s'il vous plaît

MODIFIER1:Après quelques recherches, j'ai trouvé l'initialisation de CertCreateSelfSignCertificate qui génère le certificat approprié :

CRYPT_KEY_PROV_INFO KeyProvInfo;
memset(&KeyProvInfo, 0, sizeof(KeyProvInfo));
KeyProvInfo.pwszContainerName = _T("my-container");
KeyProvInfo.pwszProvName = _T("Microsoft RSA SChannel Cryptographic Provider");
KeyProvInfo.dwProvType = PROV_RSA_SCHANNEL;
KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET;
KeyProvInfo.cProvParam = 0;
KeyProvInfo.rgProvParam = NULL;
KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;

Il vous suffit de lier un certificat à un ip:port puis d'ouvrir votre écouteur avec un préfixe https://.0.0.0.0 s'applique à toutes les adresses IP.appid est n'importe quel GUID aléatoire et certhash est le hachage du certificat (parfois appelé empreinte digitale).

Exécutez ce qui suit avec cmd.exe en utilisant les privilèges d'administrateur.

netsh http add sslcert ipport=0.0.0.0:1234 certhash=613bb67c4acaab06def391680505bae2ced4053b  appid={86476d42-f4f3-48f5-9367-ff60f2ed2cdc}

Si vous souhaitez créer un certificat auto-signé pour tester cela,

  1. Ouvrir IIS
  2. Cliquez sur le nom de votre ordinateur
  3. Cliquez sur l'icône Certificats de serveur
  4. Cliquez sur générer un certificat auto-signé
  5. Double-cliquez et allez aux détails
  6. Vous y verrez l’empreinte du pouce, supprimez simplement les espaces.

    HttpListener listener = new HttpListener();
    listener.Prefixes.Add("https://+:1234/");
    listener.Start();
    Console.WriteLine("Listening...");
    HttpListenerContext context = listener.GetContext();
    
    using (Stream stream = context.Response.OutputStream)
    using (StreamWriter writer = new StreamWriter(stream))
        writer.Write("hello, https world");
    
    Console.ReadLine();
    

Après avoir exécuté ce programme, je viens d'accéder à https://localhost:1234 pour voir le texte imprimé.Étant donné que le CN du certificat ne correspond pas à l'URL et qu'il ne se trouve pas dans le magasin de certificats de confiance, vous recevrez un avertissement de certificat.Le texte est cependant crypté comme vous pouvez le vérifier avec un outil comme Wire Shark.

Si vous souhaitez plus de contrôle sur la création d'un certificat x509 auto-signé, openssl est un excellent outil et il existe un port pour Windows.J'ai eu beaucoup plus de succès avec cet outil qu'avec l'outil makecert.


Il est également très important que si vous communiquez avec un service https à partir d'un code comportant un avertissement SSL, vous deviez configurer le validateur de certificat sur le gestionnaire de points de service pour le contourner à des fins de test.

ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, errors) => true;

Je ne l'ai pas encore entièrement implémenté, mais ce site Web semble donner une idée bonne procédure pas à pas de mise en place des certificats et du code.

Voici une autre façon de lier le certificat SSL à la combinaison IP/PORT sans utiliser httpcfg.exe (XP) ou netsh.exe (Vista+).

http://dotnetcodebox.blogspot.com.au/2012/01/how-to-work-with-ssl-certificate.html

L'essentiel est que vous pouvez utiliser un langage C++ HttpSetServiceConfiguration API intégrée à Windows pour le faire par programme plutôt que via la ligne de commande, supprimant ainsi la dépendance au système d'exploitation et installant httpcfg.

Le documentation de classe

a cette note:

Si vous créez un HTTPListener à l'aide de HTTPS, vous devez sélectionner un certificat de serveur pour cet écouteur.Sinon, une requête httpwebRequest de ce HttpListener échouera avec une fermeture inattendue de la connexion.

et ça:

Vous pouvez configurer des certificats de serveur et d'autres options d'écoute à l'aide de httpcfg.exe.Voir http://msdn.microsoft.com/library/default.asp?url=/library/en-us/http/http/httpcfg_exe.asppour plus de détails.L'exécutable est expédié avec Windows Server 2003, ou peut être construit à partir du code source disponible dans le SDK de la plate-forme.

La première note est-elle expliquée par la seconde ?Comme indiqué dans la question, j'ai utilisé httpcfg.exe pour lier le certificat à un port spécifique.S’ils ont l’intention d’autre chose que cela, la note est ambiguë.

J'ai rencontré le même problème que vous.Heureusement, après avoir cherché sur Google des étapes difficiles cette page faire fonctionner SSL avec mon HttpListener.

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