2012-02-04 8 views
17

Sto tentando di importare a livello di codice un certificato X509 (pfx/PKCS # 12) nell'archivio certificati della mia macchina locale. Questo certificato particolare, ha una catena di certificati, il percorso di certificazione simile a questa:Come importare a livello di codice un pfx con una catena di certificati nell'archivio certificati?

  • certificato Root CA
    • Organizzazione certificato CA
      • Organizzazione 2 certificato CA
        • mio certificato

Il codice che uso si presenta così:

cert = new X509Certificate2(pathToCert, password); 

if (cert != null) 
{ 
    var store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
    store.Open(OpenFlags.ReadWrite); 
    if (!store.Certificates.Contains(cert)) 
    { 
     store.Add(cert); 
    } 
} 

Questo codice fa importare il certificato, comunque sembra ignorare la catena. Se posso controllare il certificato nell'archivio, il percorso di certificazione mostra solo:

  • mio certificato

Tuttavia quando ho importare manualmente il pfx, lo fa mostrare il percorso completo. Sto saltando un passaggio qui o mi mancano alcuni parametri? Qualcuno può fare luce su questo?

+0

Un PFX viene in genere confuso con PKCS # 12, nel tuo caso vuoi solo una catena di certificati, che puoi facilmente fare con i file PEM. Ma .. hai il tuo file di chiavi private? in tal caso, si desidera PKCS # 12 – IanNorton

+0

@IanNorton: in realtà è un certificato PKCS # 12. Non è che io abbia scelta in questo. –

+0

In questo caso, si desidera leggere [questo su pkcs # 12] (http://stackoverflow.com/questions/555184/decode-a-pkcs12-file) Si dispone di un file p12 che contiene x 509 oggetti. – IanNorton

risposta

11

Si dovrebbe essere in grado di scorrere i certificati nel proprio PFX (e importarli ciascuno nel negozio CERT di propria scelta) aprendo il file PFX come oggetto X509Certificate2Collection.

Ecco la documentazione sul X509Certificate2Collection:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2collection.aspx

MSDN fornisce alcuni esempi di codice in quella pagina Documenti su come ispezionare ogni CERT della collezione.

Una volta che si conoscono i CN/emittenti/altre informazioni su ciascun certificato, è necessario chiarire quale archivio di certificati deve essere aggiunto a ciascuno di essi. Per questo è possibile utilizzare la classe X509Store e l'enumerazione StoreName per specificare quale negozio si vuole aprire/aggiungere:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509store.aspx

http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.storename.aspx

vedere anche la mia risposta a una simile domanda SO:

How to retrieve certificates from a pfx file with c#?

Come menzionato in uno dei commenti più recenti in quella risposta, quando si tenta di importare un CERT al negozio principale dell'utente corrente ("StoreName.Ro ot "e" StoreLocation.CurrentUser "come nome/posizione) si aprirà una finestra di dialogo che chiede di confermare.

Per risolvere il problema, ho aggiunto un po 'di codice di automazione dell'interfaccia utente MS al mio metodo di importazione certificato, per fare clic su OK nel prompt.

Oppure, come dice il commentatore "CodeWarrior" nell'altro commento della risposta SO, per evitare la finestra di dialogo popup è possibile provare a inserire il cert root nell'archivio di LocalMachine anziché CurrentUser.

codice di esempio:

string certPath = <YOUR PFX FILE PATH>; 
string certPass = <YOUR PASSWORD>; 

// Create a collection object and populate it using the PFX file 
X509Certificate2Collection collection = new X509Certificate2Collection(); 
collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet); 

foreach (X509Certificate2 cert in collection) 
{ 
    Console.WriteLine("Subject is: '{0}'", cert.Subject); 
    Console.WriteLine("Issuer is: '{0}'", cert.Issuer); 

    // Import the certificate into an X509Store object 
} 
+1

Questo non funziona nel mio caso, dopo l'importazione la raccolta contiene solo un certificato (My Certificate). Penso che tu sia in qualche modo però. –

+0

Ho avuto lo stesso problema in una volta (in cui l'apertura del file PFX come oggetto X509Certificate2 comportava l'importazione solo del certificato foglia/utente). Quindi X509Certificate2 a quanto pare non funziona a meno che non sia necessario solo il certificato foglia. L'apertura del PFX come X509Certificate2Collection era la soluzione: quando lo fai e controlla la lunghezza della collezione (o stampi il Soggetto/Emittente di ogni cert nella collezione in un ciclo for) vedi tutti i certificati della catena? –

+0

Finalmente mi sembra di arrivare da qualche parte. Ho fatto una nuova esportazione dal mio negozio di cert e ora sembra che funzioni con il tuo codice. Mostra tutti i certificatori ora, TRANNE il certificato di root ... Qualche idea? –

0

Un certificato X.509 contiene solo una catena che lo collega al certificato di origine (incluse le autorità intermedie), ma questi certificati non sono contenuti nel certificato. Questa catena viene utilizzata quando un certificato finale (che non è autofirmato) viene convalidato - deve portare a un certificato di origine attendibile. Più precisamente, la chiave pubblica di ogni CA viene utilizzata per decodificare e verificare l'hash per un certificato emesso. Questo processo viene ripetuto fino al raggiungimento del certificato radice. Dopo aver controllato l'intera catena, se il certificato di origine è attendibile, anche il certificato finale è considerato affidabile. Ovviamente il processo include anche altre convalide (come la data di inizio, la data di fine, la lista di revoche di certificati per esempio), ma ho indicato solo la parte relativa all'utilizzo della catena.

Quindi hai importato correttamente "Il mio certificato" insieme alla catena a "CA certificato di root" - questa catena è codificata in "Il mio certificato" e puoi confermare visualizzando le sue proprietà, ma questa catena è solo un collegamento e non contiene alcun certificato di "CA certificato di root", "CA di certificato di organizzazione" e "CA di certificato di organizzazione 2".

Spero che questo risolva il problema, ma in caso contrario, potresti essere più specifico su cosa stai cercando di realizzare?

+0

Grazie per la teoria sui certificati. Il fatto è che sto perdendo le informazioni sulla catena durante l'importazione e sto cercando di risolverlo nel mio codice. –

5

Per riferimento futuro, ho scoperto un altro modo di fare questo, utilizzando l'oggetto X509Chain:

var cert = new X509Certificate2(pathToCert, password); 

X509Chain chain = new X509Chain(); 
chain.Build(cert); 
for (int i = 0; i < chain.ChainElements.Count; i++) 
{ 
    //add to the appropriate store 
} 
+0

Qualche possibilità è possibile condividere il codice "al negozio appropriato" per rendere questa una soluzione generica? –

0

Per chi vuole "al negozio appropriato" codice generico soluzione

Questo è quello che ho creato utilizzando VB quindi non dovrebbe essere difficile portarlo a C#. Ho usato i post sopra per farmi iniziare e io sono un NoOB totale a questo.

Dim certPath = "C:\Users\08353153\Documents\Visual Studio 2015\Projects\WindowsApplication2\WindowsApplication2\bin\Debug\8870-thebigchess.pfx" 
    Dim certPass = "eduSTAR.NET" 
    Dim Collection As New X509Certificate2Collection 
    Collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet) 

    Dim certOne As X509Certificate2 = Collection(0) 
    Dim certTwo As X509Certificate2 = Collection(2) 
    Dim certThree As X509Certificate2 = Collection(1) 

    Dim personal As New X509Store(StoreName.My, StoreLocation.LocalMachine) 
    personal.Open(OpenFlags.ReadWrite) 
    personal.Add(certOne) 
    personal.Close() 

    Dim trust As New X509Store(StoreName.Root, StoreLocation.LocalMachine) 
    trust.Open(OpenFlags.ReadWrite) 
    trust.Add(certTwo) 
    trust.Close() 

    Dim intermed As New X509Store(StoreName.CertificateAuthority, StoreLocation.LocalMachine) 
    intermed.Open(OpenFlags.ReadWrite) 
    intermed.Add(certThree) 
    intermed.Close()