2014-10-24 15 views
6

Ho un servizio Windows (in esecuzione come LocalSystem) che esegue l'auto-hosting di un servizio OWIN (SignalR) e deve essere accessibile tramite SSL.Registrare il certificato nella porta SSL

Posso impostare il binding SSL sul mio computer di sviluppo locale bene - e posso accedere al mio servizio su SSL su quella stessa macchina. Tuttavia, quando vado a un'altra macchina e cercare di eseguire il seguente comando ricevo un errore:

Comando:

netsh http add sslcert ipport=0.0.0.0:9389 appid={...guid here...} certhash=...cert hash here... 

Errore:

SSL Certificate add failed, Error: 1312

A specified logon session does not exist. It may have already been terminated.

Il certificato che sto usando è completamente certificato firmato (non un certificato di sviluppo) e funziona sulla mia scatola di sviluppo locale. Ecco quello che sto facendo:

servizio di Windows viene avviato e registra il mio certificato utilizzando il seguente codice:

var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); 
store.Open(OpenFlags.ReadWrite); 
var path = AppDomain.CurrentDomain.BaseDirectory; 
var cert = new X509Certificate2(path + @"\mycert.cer"); 
var existingCert = store.Certificates.Find(X509FindType.FindByThumbprint, cert.Thumbprint, false); 
if (existingCert.Count == 0) 
    store.Add(cert); 
store.Close(); 

ho quindi tentare di associare il certificato alla porta 9389 utilizzando netsh e il seguente codice:

var process = new Process { 
    StartInfo = new ProcessStartInfo { 
     WindowStyle = ProcessWindowStyle.Hidden, 
     FileName = "cmd.exe", 
     Arguments = "/c netsh http add sslcert ipport=0.0.0.0:9389 appid={12345678-db90-4b66-8b01-88f7af2e36bf} certhash=" + cert.thumbprint 
    } 
}; 
process.Start(); 

Il codice sopra riportato installa correttamente il certificato nella cartella del certificato "Macchina locale - Certificati \ Certificazione radice attendibile \ Certificati", ma il comando netsh non viene eseguito con l'errore descritto sopra. Se prendo il comando netsh e lo eseguo in un prompt dei comandi come amministratore su quella casella, esso genera anche lo stesso errore - quindi non credo che sia un problema relativo al codice ...

Devo immaginare che questo è possibile realizzare - molte altre applicazioni creano servizi self-hosted e li ospitano su ssl - ma non riesco a farlo funzionare per niente ... qualcuno ha qualche suggerimento? Forse alternative programmatiche a netsh?

+0

ho scoperto che se ho generare un certificato auto-firmato sulla macchina che sto avendo problemi con e usa netsh sull'identificazione personale del certificato che funziona - Mi chiedo se c'è un modo per generare un certificato auto-firmato nel codice? –

+2

Si sta importando il certificato da un file .cer, che non include la chiave privata del certificato.Hai bisogno della sua chiave privata per collegarlo a una porta. Per far funzionare il tuo "certificato completamente firmato", devi esportarlo dalla macchina su cui lavora (il tuo computer di sviluppo) _alungo con la chiave privata_ in un file .pfx. Quindi importalo nella macchina su cui stai installando il servizio. Il motivo per cui un certificato autofirmato sulla macchina funziona è perché crea una chiave privata su quella macchina in cui viene generato il certificato. – Scott

risposta

3

Ok ho trovato la risposta:

Se si sta portando in un certificato da un'altra macchina che non funziona sulla nuova macchina. È necessario creare un certificato autofirmato sulla nuova macchina e importarlo nei certificati di radice attendibili del computer locale.

La risposta è da qui: How to create a self-signed certificate using C#?

Per l'amor di posteri questo è il processo utilizzato per creare un self firmato cert (dalla risposta di cui sopra si fa riferimento):

Importare il CertEnroll 1.0 Type Library dal COM scheda di riferimenti del vostro progetto

aggiungere il seguente metodo al codice:

//This method credit belongs to this StackOverflow Answer: 
//https://stackoverflow.com/a/13806300/594354 
using CERTENROLLLib; 

public static X509Certificate2 CreateSelfSignedCertificate(string subjectName) 
{ 
    // create DN for subject and issuer 
    var dn = new CX500DistinguishedName(); 
    dn.Encode("CN=" + subjectName, X500NameFlags.XCN_CERT_NAME_STR_NONE); 

    // create a new private key for the certificate 
    CX509PrivateKey privateKey = new CX509PrivateKey(); 
    privateKey.ProviderName = "Microsoft Base Cryptographic Provider v1.0"; 
    privateKey.MachineContext = true; 
    privateKey.Length = 2048; 
    privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE; // use is not limited 
    privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG; 
    privateKey.Create(); 

    // Use the stronger SHA512 hashing algorithm 
    var hashobj = new CObjectId(); 
    hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, 
     ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, 
     AlgorithmFlags.AlgorithmFlagsNone, "SHA512"); 

    // add extended key usage if you want - look at MSDN for a list of possible OIDs 
    var oid = new CObjectId(); 
    oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server 
    var oidlist = new CObjectIds(); 
    oidlist.Add(oid); 
    var eku = new CX509ExtensionEnhancedKeyUsage(); 
    eku.InitializeEncode(oidlist); 

    // Create the self signing request 
    var cert = new CX509CertificateRequestCertificate(); 
    cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, ""); 
    cert.Subject = dn; 
    cert.Issuer = dn; // the issuer and the subject are the same 
    cert.NotBefore = DateTime.Now; 
    // this cert expires immediately. Change to whatever makes sense for you 
    cert.NotAfter = DateTime.Now; 
    cert.X509Extensions.Add((CX509Extension)eku); // add the EKU 
    cert.HashAlgorithm = hashobj; // Specify the hashing algorithm 
    cert.Encode(); // encode the certificate 

    // Do the final enrollment process 
    var enroll = new CX509Enrollment(); 
    enroll.InitializeFromRequest(cert); // load the certificate 
    enroll.CertificateFriendlyName = subjectName; // Optional: add a friendly name 
    string csr = enroll.CreateRequest(); // Output the request in base64 
    // and install it back as the response 
    enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate, 
     csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); // no password 
    // output a base64 encoded PKCS#12 so we can import it back to the .Net security classes 
    var base64encoded = enroll.CreatePFX("", // no password, this is for internal consumption 
     PFXExportOptions.PFXExportChainWithRoot); 

    // instantiate the target class with the PKCS#12 data (and the empty password) 
    return new System.Security.Cryptography.X509Certificates.X509Certificate2(
     System.Convert.FromBase64String(base64encoded), "", 
     // mark the private key as exportable (this is usually what you want to do) 
     System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.Exportable 
    ); 
} 

Fo r chiunque altro leggendo questa risposta - il codice per l'importazione del certificato dalla domanda iniziale dovrebbe ora passare alla seguente:

var certName = "Your Cert Subject Name"; 
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); 
store.Open(OpenFlags.ReadWrite); 
var existingCert = store.Certificates.Find(X509FindType.FindBySubjectName, certName, false); 
if (existingCert.Count == 0) 
{ 
    var cert = CreateSelfSignedCertificate(certName); 
    store.Add(cert); 
    RegisterCertForSSL(cert.Thumbprint); 
} 
store.Close(); 
+0

Direi che è più facile usare [certutil.exe] (http://technet.microsoft.com/en-us/library/cc732443.aspx) piuttosto che scrivere il codice in C#. – abatishchev

+1

Sono andato giù per quel percorso e funziona sicuramente - tuttavia quando si esegue un installshield e si tenta di eseguire certutil si incontrano un sacco di problemi di autorizzazioni ... la cosa migliore sarebbe avere l'applicazione C# eseguire certutil da una finestra servizio in esecuzione in LocalSystem ma sinceramente preferisco in questo modo perché è più facile eseguire il debug di –

+0

Grazie. Ho provato a usare CLRSecurity ma non ha funzionato (potrei creare il certificato ma non registrarlo per qualche motivo). –

Problemi correlati