CryptoAPI - Как получить все атрибуты поля Subject?

SQL-Talker
Дата: 05.06.2019 17:33:10
Как получить все атрибуты поля Subject?
Так чтобы у меня был массив записей из 2-х параметров - имя_атрибута, значение_атрибута :
[(PropName: "CN", PropValue: "Microsoft Root Certificate Authority 2011"), ...]
Причем, как я понимаю, там могут быть совершенно нестандартные атрибуты типа ИНН, КПП и проч.
Ghost Writer
Дата: 05.06.2019 20:06:12
SQL-Talker,

самый простой способ - прочитать Subject функцией CertNameToStr. для нее есть три константы
const CERT_SIMPLE_NAME_STR = 1;
const CERT_OID_NAME_STR = 2;
const CERT_X500_NAME_STR = 3;

последние две как раз дают результат с именами атрибутов.
SQL-Talker
Дата: 05.06.2019 20:27:03
Ghost Writer,

Я получаю строку Subject таким способом, вопрос в том как распарсить эту строку
К примеру :
автор
C=US, S=California, L=San Jose, O="Adobe Systems, Incorporated", OU=Digital ID Class 3 - Microsoft Software Validation v2, OU=Acrobat Engineering, CN="Adobe Systems, Incorporated"

Стандартным SplitString(str, ',') тут не обойтись - запятые внутри значений атрибутов все ломают
С TStringList та же хрень
Подумал, может есть в API готовые функции перебора списка атрибутов
Ghost Writer
Дата: 05.06.2019 20:45:57
SQL-Talker
Подумал, может есть в API готовые функции перебора списка атрибутов
да, есть
курить надо
PCERT_NAME_INFO
PCERT_RDN
PCERT_RDN_ATTR
CertRDNValueToStr
вначале декодировать Subject как X509_UNICODE_NAME
Ghost Writer
Дата: 05.06.2019 21:00:54
SQL-Talker
получаю строку Subject таким способом, вопрос в том как распарсить эту строку

CertNameToStr с комбинацией параметров CERT_X500_NAME_STR or CERT_NAME_STR_CRLF_FLAG
SQL-Talker
Дата: 06.06.2019 11:23:08
Ghost Writer,

Набросал код:
var
  i: Integer;
  pvStructInfo: PVOID;
  cbStructInfo: DWORD;
  pCertNameInfo: PCERT_NAME_INFO;
  vRDNAttr: PCERT_RDN_ATTR;
  psz: PWideChar;
begin
  // откроем хранилище
  vCertStore := CertOpenSystemStore( 0, PChar( 'MY' ));
  try
    // ищем сертификат
    vCertContext := Cert_FindCertificate_BySHA1(PWideChar( edtSHA1FingerPrint.Text ), vCertStore);
    try
      // декодируем Subject
      if CryptDecodeObject(
        X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
        X509_UNICODE_NAME, //X509_NAME,
        vCertContext.pCertInfo.Subject.pbData,
        vCertContext.pCertInfo.Subject.cbData,
        CRYPT_DECODE_NOCOPY_FLAG,
        nil,
        @cbStructInfo
      )
      then
      begin
        GetMem(pvStructInfo, cbStructInfo);
        try
          CryptDecodeObject(
            X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
            X509_UNICODE_NAME, //X509_NAME,
            vCertContext.pCertInfo.Subject.pbData,
            vCertContext.pCertInfo.Subject.cbData,
            CRYPT_DECODE_NOCOPY_FLAG,
            pvStructInfo,
            @cbStructInfo
          );

          pCertNameInfo := PCERT_NAME_INFO(cbStructInfo);

          // перебираем массив атрибутов Subject-а
          for I := 0 to pCertNameInfo.cRDN-1 do
          begin
            vRDNAttr := pCertNameInfo.rgRDN[i].rgRDNAttr;
            CertRDNValueToStr(vRDNAttr.dwValueType, @(vRDNAttr.Value), nil, size);
            if size > 0 then
            begin
              GetMem(psz, size);
              CertRDNValueToStr(vRDNAttr.dwValueType, @(vRDNAttr.Value), psz, size);
              Memo1.Lines.Append(psz);
            end;
          end;
        finally
          FreeMem(pvStructInfo, cbStructInfo);
        end;
      end;

    finally
      Win32Check( CertFreeCertificateContext( vCertContext ));
    end;
  finally
    Win32Check( CertCloseStore( vCertStore, CERT_CLOSE_STORE_CHECK_FLAG ));
  end;
end;

Не компилируется , останавливается на первом же CryptDecodeObject и говорит - "E2033 Types of actual and formal var parameters must be identical"
Не могу понять где ошибка...
Ghost Writer
Дата: 06.06.2019 11:54:59
SQL-Talker,

предположу, что vCertContext^...

а может не мучиться ?
Ghost Writer
CertNameToStr с комбинацией параметров CERT_X500_NAME_STR or CERT_NAME_STR_CRLF_FLAG
SQL-Talker
Дата: 06.06.2019 12:27:19
Ghost Writer,

Блин, слона то и не приметил - or CERT_NAME_STR_CRLF_FLAG :))
Так конечно все сильно проще

Хотя, в принципе, хорошо бы понять почему предыдущий вариант не работает...
Ghost Writer
Дата: 06.06.2019 13:30:29
SQL-Talker,

в JwaWinCrypt у CryptDecodeObject параметр pcbStructInfo: DWORD а не PDWORD, убери @ перед cbStructInfo
SQL-Talker
Дата: 06.06.2019 14:26:15
Ghost Writer,

Убрал, больше не ругается тут
Ругается на строке
vRDNAttr := pCertNameInfo.rgRDN[i].rgRDNAttr;
E2016 Array type required

Вроде, по документации это массив
https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/ns-wincrypt-cert_name_info
rgRDN - Array of pointers to CERT_RDN structures.