KERB_SMARTCARD_CSP_INFO estrutura

A estrutura KERB_SMARTCARD_CSP_INFO contém informações sobre um fornecedor de serviços criptográficos de cartões inteligentes (CSP).

Esta estrutura não é declarada num 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, desta estrutura, incluindo quaisquer dados anexados.

TipoDeMensagem

O tipo de mensagem que está a ser transmitida. Este membro deve ser definido para 1.

Informação de Contexto

Reservado.

EspaçoDeEspaçoParaWow64

Reservado.

flags

Reservado.

KeySpec

A chave privada a usar do contentor de chaves especificado dentro do buffer bBuffer. A chave pode ser um dos seguintes valores, definidos no WinCrypt.h.

Valor 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 deve conter uma cadeia vazia.

nReaderNameOffset

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

Importante

Se o nome do leitor de cartões inteligentes não for fornecido, o buffer deve conter uma cadeia vazia.

nNomeContentorOffset

O número de caracteres no buffer bBuffer que precede o nome do contentor de chaves nesse buffer. Esta cadeia não pode estar vazia.

nCSPNameOffset

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

bBuffer

Um array de caracteres inicializado com um comprimento de sizeof(DWORD). Este buffer contém os nomes referidos pelos membros nCardNameOffset, nReaderNameOffset, nContainerNameOffset e nCSPNameOffset , bem como quaisquer dados adicionais fornecidos pelo CSP.

Quaisquer nomes que não sejam fornecidos devem ser representados neste buffer por cadeias vazias.

Observações

disposição do buffer bHand

O bBuffer começa com um marcador de lugar/prefixo de sizeof(DWORD) bytes do tamanho de DWORD e depois armazena cadeias terminadas em nulo para os nomes do cartão, leitor, contentor e CSP (cada um pode ser uma string vazia, exceto o nome do contentor que deve estar não vazio), seguido de quaisquer dados extra específicos do CSP.

Componente (ordem a partir do início do bBuffer) Description Requisito
Prefixo DWORD Reservado marcador de posição (sizeof(DWORD) = 4 bytes) Sempre presente
Nome do cartão String vazia ou nome da carta terminada por nulo Opcional
Nome do Leitor String vazia ou nome do leitor terminado por nulo Opcional
Nome do Contêiner Nome do contentor da chave terminada por nulo Obrigatório; deve ser não vazio
CSPName String vazia ou nome CSP terminado por nulo Opcional
Dados adicionais Dados anexados específicos do CSP após nomes Opcional; Formato definido pelo CSP
  • Deslocamentos:nCardNameOffset, nReaderNameOffset, nContainerNameOffset, e nCSPNameOffset são o número de caracteres desde o início até bBuffer ao início de cada cadeia respetiva. Estas contagens incluem a região reservada sizeof(DWORD) inicial e são medidas em TCHAR unidades (ANSI char ou Unicode wchar_t, dependendo da compilação).
  • Nomes vazios: Quando não é fornecido um nome, o buffer deve conter uma cadeia vazia (comprimento zero seguida pelo terminador) nessa posição.
  • Alinhamento de serialização: Quando serializados, os membros da estrutura devem estar alinhados a limites de 2 bytes.

Examples

Como KERB_SMARTCARD_CSP_INFO não é declarado num cabeçalho público, deve declará-lo por si próprio. A #pragma pack(push, 2) diretiva é necessária para garantir o alinhamento dos membros a 2 bytes quando a estrutura é serializada.

Os exemplos abaixo assumem uma construção Unicode (WCHAR / PCWSTR), pelo que 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 seguinte função auxiliar aloca e preenche uma estrutura KERB_SMARTCARD_CSP_INFO . Demonstra como calcular o tamanho total, definir os deslocamentos do bBuffer e copiar as cadeias de nomes 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 seguinte, em CreateSmartCardCspInfo conjunto com KERB_CERTIFICATE_LOGON para realizar um login interativo com cartão inteligente através do LsaLogonUser. Todos os campos do 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;
}

Requerimentos

Requisito Valor
Cliente mínimo suportado
Windows Vista [apenas aplicações de ambiente de trabalho]
Servidor mínimo suportado
Windows Server 2008 [apenas aplicações de ambiente de trabalho]

Consulte também

KERB_CERTIFICATE_LOGON