2017-05-17 3 views
0

THTTPRIO-Komponente, in der HTTPWebNode -Eigenschaft, wenn Sie in ClientCertificate klicken, öffnet Delphi ein Formular, um das Zertifikat auszuwählen und seine Informationen in den Eigenschaften der Komponente zu laden. Ist das ein Windows-Bildschirm? Wenn ja, wie kann ich es benutzen? Heute verwende ich SecureBlackBox, um die Zertifikate in einer Combobox zu laden, aber ich würde gerne wissen, ob es möglich ist, diesen Bildschirm zu verwenden. DankWie rufe ich den Standard-Windows-Bildschirm auf, um ein Zertifikat auszuwählen?

Screen to choose certificate

UPDATE

konnte ich den Dialog zeigen, die ms Funktion CryptUIDlgSelectCertificateFromStore Verwendung JWAPI verwenden. Jetzt habe ich Probleme mit dem Ergebnis der Funktion, der PCCERT_CONTEXT-Struktur.

var 
    P: Pointer; 
    Context: PCCERT_CONTEXT; 
    Issuer: DATA_BLOB; 

    function GetDataBlobText(Data: DATA_BLOB): string; 
    begin 
    SetString(Result, PAnsiChar(Data.pbData), Data.cbData div SizeOf(AnsiChar)); 
    end; 

begin 
    P := CertOpenSystemStore(0, 'MY'); 
    Context := CryptUIDlgSelectCertificateFromStore(P, 0, PChar('test'), nil, CRYPTUI_SELECT_ISSUEDTO_COLUMN, 0, nil); 
    if Context <> nil then 
    begin 
    Issuer := Context.pCertInfo.Issuer; 
    ShowMessage((GetDataBlobText(Issuer))); 
    end; 
end; 

Das Ergebnis in Showmessage ist:

UPDATE2

Dank @RbMm. Um Zeichenfolge von ASN Codierung Felder (Issuer und Betreff)

var 
    P: Pointer; 
    Context: PCCERT_CONTEXT; 
    Subject: DATA_BLOB; 
    SubjectStr: string; 
    size : Cardinal; 
begin 
    P := CertOpenSystemStore(0, PAnsiChar('MY')); 
    Context := CryptUIDlgSelectCertificateFromStore(P, 0, 'test', 'select certificate', 
    CRYPTUI_SELECT_ISSUEDTO_COLUMN, 0, nil); 
    if Context <> nil then 
    begin 
    Subject := Context.pCertInfo.Subject; 
    size := CertNameToStr(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, @Subject, CERT_X500_NAME_STR, 0, 0); 
    SetString(SubjectStr, PAnsiChar(Subject.pbData), size); 
    CertNameToStr(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, @Subject, CERT_X500_NAME_STR, PAnsiChar(SubjectStr), size); 
    Result := SubjectStr; 
    end; 

Um die Zeichenfolge von Rohdatenblock (Serial) zu erhalten:

var 
    SerialNumber: CRYPT_INTEGER_BLOB; 
    size : Cardinal; 
    s: PWideChar; 
    ss: string; 
begin 
SerialNumber := Context.pCertInfo.SerialNumber; 
CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, nil, size); 
s := AllocMem(SizeOf(Char) * size); 
CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, s, size); 
ss := s; 
showmessage(ss); 
FreeMem(s, SizeOf(Char) * size); 
+0

Task-Managers, um herauszufinden, welcher Prozess der Dialog angezeigt wird. Mit einem Debugger an den Prozess anhängen. Stoppen Sie den Prozess und schauen Sie sich den Stack-Trace an. Sie sollten in der Lage sein, Symbole für alle Microsoft-Komponenten zu erhalten, und von dort sollten Sie in der Lage sein, zu sehen, ob es eine API gibt, die Sie verwenden können, oder wenn nicht. –

+3

Dieser Dialog wird erstellt von [CryptUIDlgSelectCertificateFromStore] (https://msdn.microsoft.com/en-us/library/windows/desktop/aa380288 (v = vs.85) .aspx) – RbMm

+0

Dank @RbMm, konnte ich zeige den Dialog an. Jetzt habe ich Probleme beim Anzeigen des Ergebnisses der Funktion, der PCCERT_CONTEXT-Struktur. Ich werde meine Frage damit aktualisieren. –

Antwort

1

alle Daten Blobs in Zertifikat verschlüsselt. also musst du es entschlüsseln. im Allgemeinen mit CryptDecodeObjectEx api. jedoch für Issuer (d. h. CERT_NAME_BLOB) dekodieren Sie können auch CertNameToStrW verwenden. Erst nachdem ein codierter Name in einer Struktur CERT_NAME_BLOB in eine mit Null abgeschlossene Zeichenkette konvertiert wurde, können Sie sie drucken. Codebeispiel auf c/C++:

void PrintIssuer(PCCERT_CONTEXT Context) 
{ 
    CERT_NAME_BLOB Issuer = Context->pCertInfo->Issuer; 

    // option #1 
    if (ULONG len = CertNameToStrW(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &Issuer, CERT_X500_NAME_STR, 0, 0)) 
    { 
     PWSTR sz = (PWSTR)alloca(len * sizeof(WCHAR)); 

     if (CertNameToStrW(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &Issuer, CERT_X500_NAME_STR, sz, len)) 
     { 
      DbgPrint("%S\n", sz); 
     } 
    } 

    // option #2 
    PCERT_NAME_INFO pcni; 
    ULONG size; 

    if (CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_NAME, Issuer.pbData, Issuer.cbData, 
     CRYPT_DECODE_ALLOC_FLAG, 0, &pcni, &size)) 
    { 
     if (DWORD cRDN = pcni->cRDN) 
     { 
      PCERT_RDN rgRDN = pcni->rgRDN; 
      do 
      { 
       if (DWORD cRDNAttr = rgRDN->cRDNAttr) 
       { 
        PCERT_RDN_ATTR rgRDNAttr = rgRDN->rgRDNAttr; 
        do 
        { 
         DbgPrint("ObjId = %s\n", rgRDNAttr->pszObjId); 

         switch (rgRDNAttr->dwValueType) 
         { 
         case CERT_RDN_PRINTABLE_STRING: 
          DbgPrint("Value = %s\n", rgRDNAttr->Value.pbData); 
          break; 
         } 

        } while (rgRDNAttr++, --cRDNAttr); 
       } 

      } while (rgRDN++, --cRDN); 
     } 

     LocalFree(pcni); 
    } 
} 

und Ausgang

CN=*** 
ObjId = 2.5.4.3 
Value = *** 

(die Zeichenfolge nach CN = und Wert = das gleiche ist)

können Sie beachten, dass "2.5.4.3" ist szOID_COMMON_NAME oder "CN". also zuerst api wird angehängt CN = vor Ausstellernamen. zweite Variante Rückkehr Sie benennen und weitere ObjId = 2.5.4.3


konvertieren Serial in druckbare Zeichenfolge kann neben Art und Weise:

CRYPT_INTEGER_BLOB SerialNumber = Context->pCertInfo->SerialNumber; 
DWORD cb = 0; 
if (CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, 0, &cb)) 
{ 
    PWSTR sz = (PWSTR)alloca(cb * sizeof(WCHAR)); 
    if (CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, sz, &cb)) 
    { 
     DbgPrint("%S\n", sz); 
    } 
} 
+0

Danke @RbMm. Ich konnte die Felder abrufen, die nicht codiert sind (Issuer und Subject oder CommonName), aber die zweite Option für codierte Felder funktionierte nicht. Ich werde meine Frage mit dem, was ich getan habe, aktualisieren. –

+0

@RodrigoCaetano der Emittent ist immer in * asn * codiert. * CertNameToStrW * Aufruf * CryptDecodeObjectEx * intern. diese 2 api geben einfach ein wenig anders aus. ein Präfix den Namen des Ausstellers, eine andere Rückkehr zu Ihnen oid Zeichenfolge – RbMm

+0

Got it. Aber kann ich die SerialNumber (d. H.) Mit der ersten Option erhalten? Wenn ich es benutze, gibt es mir eine leere Saite zurück. Was ich brauche, ist nur eine Kennung für das Zertifikat zu erhalten, in meinem Code zu verwenden. Ich kann das Zertifikat selbst mit einer Delphi-Komponente SecureBlackBox bekommen, aber ich möchte nur diese dlg verwenden, damit der Benutzer einen auswählen kann, und dann den Bezeichner, der in der Liste der von der Komponente zurückgegebenen Zertifikate ausgewählt wurde. –

Verwandte Themen