estrutura KERB_SMARTCARD_CSP_INFO

A estrutura KERB_SMARTCARD_CSP_INFO contém informações sobre um CSP ( provedor de serviços criptográficos ) de cartão inteligente.

Essa estrutura não é declarada em um cabeçalho público.

Sintaxe

typedef struct _KERB_SMARTCARD_CSP_INFO {
  DWORD dwCspInfoLen;
  DWORD MessageType;
  union {
    PVOID   ContextInformation;
    ULONG64 SpaceHolderForWow64;
  };
  DWORD flags;
  DWORD KeySpec;
  ULONG nCardNameOffset;
  ULONG nReaderNameOffset;
  ULONG nContainerNameOffset;
  ULONG nCSPNameOffset;
  TCHAR bBuffer;
} KERB_SMARTCARD_CSP_INFO, *PKERB_SMARTCARD_CSP_INFO;

Members

dwCspInfoLen

O tamanho, em bytes, dessa estrutura, incluindo todos os dados acrescentados.

MessageType

O tipo de mensagem que está sendo passada. Esse membro deve ser definido como 1.

Contextinformation

Reservado.

SpaceHolderForWow64

Reservado.

flags

Reservado.

KeySpec

A chave privada a ser usada do contêiner de chave especificado no bBuffer do buffer. A chave pode ser um dos seguintes valores, definidos em WinCrypt.h.

Value Meaning
AT_KEYEXCHANGE
1
A chave é uma chave de troca de chaves.
AT_SIGNATURE
2
A chave é uma chave de assinatura.

nCardNameOffset

O número de caracteres no buffer bBuffer que precede o nome do cartão inteligente nesse buffer.

Importante

Se o nome do cartão inteligente não for fornecido, o buffer deverá conter uma cadeia de caracteres vazia.

nReaderNameOffset

O número de caracteres no buffer bBuffer que precede o nome do leitor de cartão inteligente nesse buffer.

Importante

Se o nome do leitor de cartão inteligente não for fornecido, o buffer deverá conter uma cadeia de caracteres vazia.

nContainerNameOffset

O número de caracteres no buffer bBuffer que precede o nome do contêiner de chave nesse buffer. Essa cadeia de caracteres não pode estar vazia.

nCSPNameOffset

O número de caracteres no buffer bBuffer que precede o nome do CSP nesse buffer.

bBuffer

Uma matriz de caracteres inicializada em um comprimento de sizeof(DWORD). Esse buffer contém os nomes referenciados pelos membros nCardNameOffset, nReaderNameOffset, nContainerNameOffset e nCSPNameOffset , bem como quaisquer dados adicionais fornecidos pelo CSP.

Todos os nomes que não são fornecidos devem ser representados nesse buffer por cadeias de caracteres vazias.

Observações

layout do bBuffer

O bBuffer começa com um espaço reservado/prefixo do tamanho de DWORD de sizeof(DWORD) bytes e armazena cadeias de caracteres terminadas em nulo para os nomes de cartão, leitor, contêiner e CSP (cada um pode ser uma cadeia de caracteres vazia, exceto o nome do contêiner que deve ser não vazio), seguido por quaisquer dados extras específicos do CSP.

Componente (ordem do início do bBuffer) Description Requirement
Prefixo DWORD Espaço reservado (sizeof(DWORD) = 4 bytes) Sempre presente
CardName Cadeia de caracteres vazia ou nome do cartão encerrado em nulo Opcional
ReaderName Nome do leitor de cadeia de caracteres vazia ou terminada em nulo Opcional
Nome do Contêiner Nome do contêiner de chave terminada em nulo Necessário; deve ser não vazio
CSPName Cadeia de caracteres vazia ou nome CSP encerrado em nulo Opcional
Dados adicionais Dados anexados específicos do CSP após nomes Opcional; Formato definido por CSP
  • Deslocamentos:nCardNameOffset, nReaderNameOffset, nContainerNameOffsete nCSPNameOffset são o número de caracteres do início bBuffer ao início de cada cadeia de caracteres respectiva. Essas contagens incluem a região reservada inicial e são medidas sizeof(DWORD) em TCHAR unidades (ANSI char ou Unicode wchar_t, dependendo do build).
  • Nomes vazios: Quando um nome não é fornecido, o buffer deve conter uma cadeia de caracteres vazia (comprimento zero seguido pelo terminador) nessa posição.
  • Alinhamento de serialização: Quando serializados, os membros da estrutura devem ser alinhados aos limites de 2 bytes.

Exemplos

Como KERB_SMARTCARD_CSP_INFO não é declarado em um cabeçalho público, você deve declará-lo por conta própria. A #pragma pack(push, 2) diretiva é necessária para garantir o alinhamento de membro de 2 bytes quando a estrutura é serializada.

Os exemplos a seguir pressupõem um build Unicode (WCHAR / PCWSTR), portanto, os deslocamentos são medidos em WCHAR unidades.

#pragma pack(push, 2)
typedef struct _KERB_SMARTCARD_CSP_INFO {
    DWORD   dwCspInfoLen;
    DWORD   MessageType;
    union {
        PVOID   ContextInformation;
        ULONG64 SpaceHolderForWow64;
    };
    DWORD   flags;
    DWORD   KeySpec;
    ULONG   nCardNameOffset;
    ULONG   nReaderNameOffset;
    ULONG   nContainerNameOffset;
    ULONG   nCSPNameOffset;
    WCHAR   bBuffer;
} KERB_SMARTCARD_CSP_INFO, *PKERB_SMARTCARD_CSP_INFO;
#pragma pack(pop)

A função auxiliar a seguir aloca e popula uma estrutura de KERB_SMARTCARD_CSP_INFO . Ele demonstra como calcular o tamanho total, definir os deslocamentos do bBuffer e copiar as cadeias de caracteres de nome para o buffer.

// Returns a LocalAlloc'd KERB_SMARTCARD_CSP_INFO, or NULL on failure.
// The caller must free the returned pointer with LocalFree.
//
// szContainerName must be non-empty. All other name parameters may be L"".
PKERB_SMARTCARD_CSP_INFO CreateSmartCardCspInfo(
    _In_ PCWSTR szCardName,       // Smart card name, or L"" if not available
    _In_ PCWSTR szReaderName,     // Card reader name, or L"" if not available
    _In_ PCWSTR szContainerName,  // Key container name (required)
    _In_ PCWSTR szCspName,        // CSP/KSP name, or L"" to let Windows choose
    _In_ DWORD  dwKeySpec)        // AT_KEYEXCHANGE or AT_SIGNATURE
{
    if (!szCardName || !szReaderName || !szContainerName || !szCspName ||
        szContainerName[0] == L'\0')
    {
        return NULL;
    }

    // Compute the length of each name, including its null terminator.
    ULONG cchCard      = (ULONG)wcslen(szCardName)      + 1;
    ULONG cchReader    = (ULONG)wcslen(szReaderName)    + 1;
    ULONG cchContainer = (ULONG)wcslen(szContainerName) + 1;
    ULONG cchCsp       = (ULONG)wcslen(szCspName)       + 1;

    // bBuffer begins with a sizeof(DWORD)-byte reserved prefix (= 2 WCHARs in
    // Unicode builds), followed by the four null-terminated name strings.
    const ULONG cchPrefix = sizeof(DWORD) / sizeof(WCHAR); // = 2
    ULONGLONG cchBuf = (ULONGLONG)cchPrefix + cchCard + cchReader + cchContainer + cchCsp;

    // Total byte size = fixed header fields up to bBuffer, plus string data.
    ULONGLONG cbTotal = FIELD_OFFSET(KERB_SMARTCARD_CSP_INFO, bBuffer)
                      + cchBuf * sizeof(WCHAR);
    if (cbTotal > MAXDWORD)
        return NULL;

    PKERB_SMARTCARD_CSP_INFO p =
        (PKERB_SMARTCARD_CSP_INFO)LocalAlloc(LPTR, (SIZE_T)cbTotal);
    if (!p)
        return NULL;

    p->dwCspInfoLen = (DWORD)cbTotal;
    p->MessageType  = 1;         // Must always be 1.
    p->KeySpec      = dwKeySpec;

    // Each offset is the number of WCHARs from the start of bBuffer to the
    // beginning of the corresponding name string.
    p->nCardNameOffset      = cchPrefix;
    p->nReaderNameOffset    = p->nCardNameOffset      + cchCard;
    p->nContainerNameOffset = p->nReaderNameOffset    + cchReader;
    p->nCSPNameOffset       = p->nContainerNameOffset + cchContainer;

    // Copy names into bBuffer at the computed offsets.
    // The 2-WCHAR prefix region is already zeroed by LPTR.
    PWCH buf = &p->bBuffer;
    wcscpy_s(buf + p->nCardNameOffset,      cchCard,      szCardName);
    wcscpy_s(buf + p->nReaderNameOffset,    cchReader,    szReaderName);
    wcscpy_s(buf + p->nContainerNameOffset, cchContainer, szContainerName);
    wcscpy_s(buf + p->nCSPNameOffset,       cchCsp,       szCspName);

    return p;
}

O exemplo a seguir usa CreateSmartCardCspInfo junto com KERB_CERTIFICATE_LOGON para executar um logon de cartão inteligente interativo via LsaLogonUser. Todos os campos de tipo ponteiro em KERB_CERTIFICATE_LOGON são armazenados como deslocamentos de bytes relativos ao início da estrutura, não como ponteiros absolutos.

// Performs an interactive smart card logon.
// On success, *phToken receives a handle to the logon token.
NTSTATUS SmartCardCertLogon(
    _In_  PCWSTR  szPin,
    _In_  PCWSTR  szCardName,
    _In_  PCWSTR  szReaderName,
    _In_  PCWSTR  szContainerName,
    _In_  PCWSTR  szCspName,
    _Out_ PHANDLE phToken)
{
    PKERB_SMARTCARD_CSP_INFO pCspInfo = CreateSmartCardCspInfo(
        szCardName, szReaderName, szContainerName, szCspName, AT_KEYEXCHANGE);
    if (!pCspInfo)
        return STATUS_NO_MEMORY;

    // Build a single contiguous buffer:
    //   [KERB_CERTIFICATE_LOGON | PIN string | KERB_SMARTCARD_CSP_INFO]
    ULONG cbLogon = sizeof(KERB_CERTIFICATE_LOGON);
    ULONG cbPin   = ((ULONG)wcslen(szPin) + 1) * sizeof(WCHAR);
    ULONG cbCsp   = pCspInfo->dwCspInfoLen;
    ULONG cbTotal = cbLogon + cbPin + cbCsp;

    NTSTATUS status = STATUS_NO_MEMORY;
    PBYTE pBuf = (PBYTE)LocalAlloc(LPTR, cbTotal);
    if (pBuf)
    {
        PKERB_CERTIFICATE_LOGON pLogon = (PKERB_CERTIFICATE_LOGON)pBuf;
        PWCH  pPinDst = (PWCH)(pBuf + cbLogon);
        PBYTE pCspDst =        pBuf + cbLogon + cbPin;

        wcscpy_s(pPinDst, cbPin / sizeof(WCHAR), szPin);
        memcpy(pCspDst, pCspInfo, cbCsp);

        // Pointer fields are stored as byte offsets relative to pBuf.
        pLogon->MessageType       = KerbCertificateLogon;
        pLogon->Pin.Length        = (USHORT)(wcslen(szPin) * sizeof(WCHAR));
        pLogon->Pin.MaximumLength = (USHORT)cbPin;
        pLogon->Pin.Buffer        = (PWSTR)(ULONG_PTR)cbLogon;
        pLogon->CspDataLength     = cbCsp;
        pLogon->CspData           = (PUCHAR)(ULONG_PTR)(cbLogon + cbPin);

        HANDLE hLsa;
        status = LsaConnectUntrusted(&hLsa);
        if (status >= 0)
        {
            LSA_STRING packageName;
            ULONG authPackage;
            RtlInitString(&packageName, MICROSOFT_KERBEROS_NAME_A);
            status = LsaLookupAuthenticationPackage(
                hLsa, &packageName, &authPackage);
            if (status >= 0)
            {
                LSA_STRING   origin      = {};
                TOKEN_SOURCE tokenSource = {};
                PVOID        pProfile   = NULL;
                ULONG        cbProfile  = 0;
                LUID         logonId;
                QUOTA_LIMITS quotas;
                NTSTATUS     subStatus;

                RtlInitString(&origin, "LogonOrigin");
                memcpy(tokenSource.SourceName, "SmartCrd", TOKEN_SOURCE_LENGTH);
                AllocateLocallyUniqueId(&tokenSource.SourceIdentifier);

                status = LsaLogonUser(
                    hLsa, &origin, Interactive, authPackage,
                    pBuf, cbTotal, NULL, &tokenSource,
                    &pProfile, &cbProfile, &logonId, phToken,
                    &quotas, &subStatus);

                if (status >= 0 && pProfile != NULL)
                    LsaFreeReturnBuffer(pProfile);
                else if (subStatus < 0)
                    status = subStatus;
            }
            LsaDeregisterLogonProcess(hLsa);
        }
        LocalFree(pBuf);
    }

    LocalFree(pCspInfo);
    return status;
}

Requirements

Requirement Value
Cliente mínimo com suporte
Windows Vista [somente aplicativos da área de trabalho]
Servidor mínimo com suporte
Windows Server 2008 [somente aplicativos da área de trabalho]

Consulte também

KERB_CERTIFICATE_LOGON