Problemi con i certificati X509Store. Trova FindByThumbprint


84

Ho un problema quando utilizzo il metodo X509Store.Certificates.Find

public static X509Certificate2 FromStore(StoreName storeName, 
          StoreLocation storeLocation, X509FindType findType, string findValue)
{
    X509Store store = new X509Store(storeName, storeLocation);
    store.Open(OpenFlags.ReadOnly);
    try
    {
        //findValue = "7a6fa503ab57b81d6318a51ca265e739a51ce660"
        var results = store.Certificates.Find(findType, findValue, true);

        return results[0];                
    }
    finally
    {
        store.Close();
    }
}

In questo caso il metodo Find restituisce 0 risultati ( results.Count == 0), ma se metto findValue come costante il metodo trova il certificato.

public static X509Certificate2 FromStore(StoreName storeName, 
           StoreLocation storeLocation, X509FindType findType, string findValue)
{
    X509Store store = new X509Store(storeName, storeLocation);
    store.Open(OpenFlags.ReadOnly);
    try
    {         
        //findValue= "7a6fa503ab57b81d6318a51ca265e739a51ce660"
        var results = store.Certificates.Find(findType, 
                              "7a6fa503ab57b81d6318a51ca265e739a51ce660", true);
        return results[0];
    }
    finally
    {
        store.Close();
    }
}

Risposte:


136

Suppongo che tu abbia copiato e incollato l'identificazione personale dalla finestra di dialogo delle informazioni sul certificato di Windows nel tuo codice (o in un file di configurazione se questo è un esempio semplificato). Fastidiosamente, il primo carattere nella casella di testo dell'identificazione personale è il carattere di controllo invisibile Unicode "segno da sinistra a destra" . Prova a selezionare le virgolette della stringa di apertura e il primo carattere dell'identificazione personale, eliminandole (eliminando anche il carattere invisibile intermedio) e riscrivendole a mano.


Anch'io sono stato sottoposto a questo strano comportamento oggi e mi ci è voluta più di un'ora per capirlo. Il modo in cui finalmente l'ho visto è stato usando il debugger per controllare le lunghezze e i codici hash di findValuee Thumbprintdell'oggetto certificato, che si è rivelato diverso. Questo mi ha portato a ispezionare gli array di caratteri di quelle stringhe nel debugger, dove appariva il carattere invisibile.


4
Un modo più semplice della riscrittura consiste nel copiare l'identificazione personale dalla finestra di dialogo della console di gestione dei certificati e incollarla in un editor di testo (come Notepad ++), a quel punto il carattere Unicode invisibile apparirà come un "?" o qualche altro personaggio ovviamente strano. Puoi quindi annullare quel carattere e copiare la stringa 'aggiornata' nel tuo codice / configurazione / casella di testo.
nateirvin

2
@nateirvin: Vero (il mio suggerimento di ridigitare a mano è un po 'eccessivo, ed è stato ispirato da quanto fossi frustrato a quel punto) - oppure incollalo in modalità UTF-8 e attiva la visualizzazione dei caratteri nascosti (il che è ancora più interessante perché ti mostra esattamente quale personaggio è).
Aasmund Eldhuset

1
@ James credo che verrà cancellato se elimini anche le virgolette circostanti (come ho scritto), ma in effetti, l'eliminazione dell'intera riga dovrebbe sicuramente eliminarla.
Aasmund Eldhuset

1
Bug documentato qui support.microsoft.com/en-us/kb/2023835 lezione è non copiare e incollare da MMC
Darryl Braaten

3
per la cronaca l'identificazione personale non fa distinzione tra maiuscole e minuscole. anche in VS2015 e nel blocco note sono stato in grado di premere Elimina per eliminare il carattere invisibile - e verificare che fosse lì in primo luogo con i tasti cursore
Simon_Weaver

50

Ho preso alcune delle risposte qui e le ho combinate in un metodo statico che si occupa di rimuovere tutti i caratteri speciali e le maiuscole. Si spera che qualcun altro possa usarlo.

    public static X509Certificate2 GetCertificate(string thumbprint)
    {
        // strip any non-hexadecimal values and make uppercase
        thumbprint = Regex.Replace(thumbprint, @"[^\da-fA-F]", string.Empty).ToUpper();
        var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

        try
        {
            store.Open(OpenFlags.ReadOnly);

            var certCollection = store.Certificates;
            var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
            if (signingCert.Count == 0)
            {
                throw new FileNotFoundException(string.Format("Cert with thumbprint: '{0}' not found in local machine cert store.", thumbprint));
            }

            return signingCert[0];
        }
        finally
        {
            store.Close();
        }
    }

2
Questo dovrebbe essere accettato come risposta. Funziona perfettamente !!
Aster Veigas

6
Quella Regex.Replace dovrebbe essere "[^ \ da-fA-F]" - le impronte digitali sono stringhe esadecimali.
Ross Patterson

Grazie, che Regex ha appena risolto il problema che avevo dopo aver insegnato al codice per mezz'ora.
Frans

Bella regex per affrontare quel fastidioso voodoo di personaggi segreti nascosti ...
granadaCoder

23

Ho avuto lo stesso problema e l'ho risolto:

  1. Ho copiato l'impronta digitale da mmc direttamente a VS. Ho confrontato le corde e non ho trovato alcuna differenza.

  2. Controllando la lunghezza con hash.length, c'è stata una differenza, 41 contro 40.

C'è un carattere invisibile aggiunto alla stringa copiandolo da mmc.


Risoluzione:

  1. copia l'impronta digitale da mmc a Notepad.exe
  2. copia di nuovo questa stringa
  3. incolla il tuo codice

Sta funzionando.


10

Anche questo mi ha fatto inciampare, ho scritto questa funzione per pulire l'identificazione personale quando copiata e incollata da MMC:

public string CleanThumbprint(string mmcThumbprint)
    {
        //replace spaces, non word chars and convert to uppercase
        return Regex.Replace(mmcThumbprint, @"\s|\W", "").ToUpper();
    }

...
        var myThumbprint = CleanThumbprint("‎b3 ab 84 e5 1e e5 e4 75 e7 a5 3e 27 8c 87 9d 2f 05 02 27 56");
        var myCertificate = certificates.Find(X509FindType.FindByThumbprint, myThumbprint, true)[0];

9

Sono caduto vittima di questo. Non solo c'era un carattere Unicode "da sinistra a destra" nella visualizzazione snap-in della console di Windows dell'identificazione personale, ma aveva anche caratteri esadecimali minuscoli, con spazi tra ogni due caratteri. L'output di CertUtil aveva anche caratteri minuscoli e spazi. Per ottenere una corrispondenza, ho dovuto specificare findValue come una stringa che è stata trasformata in

  1. Rimuovi il carattere speciale iniziale,
  2. Rimuovi lo spazio vuoto tra i gruppi di caratteri,
  3. Cambia tutti i caratteri in maiuscolo .

3

Questo codice dovrebbe funzionare.

Suppongo che tu abbia copiato questa identificazione personale dalla console di gestione dei certificati. E quel valore copiato contiene un simbolo unicode non leggibile che è invisibile in Visual Studio. Prova a cancellare il primo simbolo invisibile e se questo è ciò a cui penso, dovrebbe funzionare.


2

Mi sono imbattuto in questa stessa cosa. Non sono riuscito a trovare questa risposta da nessuna parte qui, quindi la posterò. Sembra che per me la funzione di ricerca di X509Store fosse semplicemente piatta non funzionante. L'ho verificato con un semplice ciclo for e recuperando manualmente il certificato.

  X509Store store = new X509Store(StoreName.Root,StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly);
        X509Certificate cert = new X509Certificate();
        for (int i = 0; i < store.Certificates.Count; i++)
        {
            if (store.Certificates[i].SerialNumber == "XXXX")
            {
                cert = store.Certificates[i];
            }
        }

1

Sostituisci il codice per trovare il tuo certificato nel negozio come di seguito:

var results = store.Certificates.Find(findType, findValue, true); 

Anche il 3 ° parametro che è bool restituisce i certificati solo se il certificato è valido. Quindi assicurati che il tuo certificato sia valido. Se hai un certificato autofirmato o giù di lì, passa il terzo parametro per essere "falso"


Il certificato è valido, perché quando un put hardcoded il metodo restituisce 1 valore var results = store.Certificates.Find (findType, "7a6fa503ab57b81d6318a51ca265e739a51ce660", true); //result.Count = 1 :)
nunofamel

Puoi controllare qual è l'ID identificazione personale che viene passato in fase di esecuzione al metodo?
Rajesh

è corretto li metto su finestre Imediate, e ha lo stesso valore :(
nunofamel

Hai cambiato la sintassi con quella mostrata sopra nel tuo codice?
Rajesh

Ora in inglese :) Il codice originale nella mia applicazione è come il precedente, era solo un errore di copia + incolla :)
nunofamel

1

Ecco la versione semplice del codice per i suggerimenti di cui sopra, naturalmente che ha funzionato per me

 private X509Certificate2 GetCertificate()
    {
        var certStore = new X509Store("my");
        certStore.Open(OpenFlags.ReadOnly);
        try
        {
            const string thumbprint = "18 33 fe 3a 67 d1 9e 0d f6 1e e5 d5 58 aa 8a 97 8c c4 d8 c3";
            var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint,
            Regex.Replace(thumbprint, @"\s+", "").ToUpper(), false);
            if (certCollection.Count > 0)
                return certCollection[0];
        }
        finally
        {
            certStore.Close();
        }
        return null;
    }

1

Incontro anche questo carattere Unicode invisibile. Anche provare a usare Blocco note (Windows 10) in qualche modo non ha funzionato bene per me. Infine, utilizzo PowerShell per ottenere l'esadecimale dell'identificazione personale pulita:

PS C:\> $tp= (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Subject -match "mycert"}).Thumbprint;
PS C:\> $tp

Tanto per il carattere Unicode.


0
var results = store.Certificates.Find(findType, findType, true);

Penso che tu intenda che il secondo parametro sia "findValue".


il 2 ° parametro è davvero findValue,
nunofamel

Se è così, il problema è altrove. Una stringa letterale rispetto a un parametro variabile di stringa non si interromperà in questo modo a meno che il contenuto effettivo non sia diverso (spazio bianco? Nuova riga finale?)
Joe

0

Solo per farti sapere qual è il personaggio invisibile, vedo che l'identificazione personale nel mmc è: 75 3a ...

Quindi lo copio e incollo nel mio vim, vedo quanto segue:

<200e> 75 3a ...

Quindi, dopo aver eliminato il primo carattere "<200e>" e gli spazi extra, starai bene.


0

+1 per la risposta di Aasmund Eldhuset (e altre risposte).

Fastidiosamente, il primo carattere nella casella di testo dell'identificazione personale è il carattere di controllo invisibile Unicode "segno da sinistra a destra".

Può essere difficile verificare che sia presente. Ad esempio, la copia dell'identificazione personale dal mio file di configurazione all'editor binario VS a volte ottiene il carattere invisibile ea volte no.

Anche questo codice non è riuscito a mostrare un problema. Ho letto il codice e ho spostato il mouse su x509Store per trovare il certificato che volevo.

                X509Certificate2 cert2 = null;
                string storeName = StoreName.My.ToString();
                var x509Store = new X509Store(storeName, StoreLocation.LocalMachine);
                x509Store.Open(OpenFlags.ReadOnly);

                var cert3 = x509Store.Certificates[4];
                var thumbprint3 = cert3.Thumbprint;
                int gotIt = thumbprint3.CompareTo(clientCert);

0

Dopo una lunga analisi, ecco cosa ha funzionato per me.

  1. Copia la miniatura dal certificato al blocco note.
  2. Copia la stampa del pollice dal blocco note allo studio visivo.
  3. Esegui Visual Studio come amministratore.

Funziona come un fascino.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.