Logos King
Logos King

Reputation: 159

What causes SEC_E_INVALID_TOKEN?

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
#include <schannel.h>
#include <shlwapi.h>
#include <assert.h>
#include <stdio.h>
#include <iostream>

#pragma comment (lib, "ws2_32.lib")
#pragma comment (lib, "secur32.lib")
#pragma comment (lib, "shlwapi.lib")

#define TLS_MAX_PACKET_SIZE (16384+512) // payload + extra over head for header/mac/padding (probably an overestimate)

typedef struct {
    SOCKET sock;
    CredHandle handle;
    CtxtHandle context;
    SecPkgContext_StreamSizes sizes;
    int received;    // byte count in incoming buffer (ciphertext)
    int used;        // byte count used from incoming buffer to decrypt current packet
    int available;   // byte count available for decrypted bytes
    char* decrypted; // points to incoming buffer where data is decrypted inplace
    char incoming[TLS_MAX_PACKET_SIZE];
} tls_socket;


int main() {
    const char* hostname = "api.openai.com";
    //const char* hostname = "badssl.com";
    //const char* hostname = "expired.badssl.com";
    //const char* hostname = "wrong.host.badssl.com";
    //const char* hostname = "self-signed.badssl.com";
    //const char* hostname = "untrusted-root.badssl.com";
    const char* path = "/";

    tls_socket s;
    // initialize windows sockets
    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
        return -1;
    }

    // create TCP IPv4 socket
    s.sock = socket(AF_INET, SOCK_STREAM, 0);
    if (s.sock == INVALID_SOCKET) {
        WSACleanup();
        return -1;
    }

    char sport[64];
    wnsprintfA(sport, sizeof(sport), "%u", 443);

    // connect to server
    if (!WSAConnectByNameA(s.sock, hostname, sport, NULL, NULL, NULL, NULL, NULL, NULL))
    {
        closesocket(s.sock);
        WSACleanup();
        return -7;
    }

    // initialize schannel
    {
        SCHANNEL_CRED cred {};
        cred
            .dwVersion = SCHANNEL_CRED_VERSION;
        cred    .dwFlags = SCH_USE_STRONG_CRYPTO          // use only strong crypto alogorithms
                     | SCH_CRED_AUTO_CRED_VALIDATION  // automatically validate server certificate
                     | SCH_CRED_NO_DEFAULT_CREDS;     // no client certificate authentication
            cred.grbitEnabledProtocols = SP_PROT_TLS1_2;  // allow only TLS v1.2
        

        if (AcquireCredentialsHandleA(NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &s.handle, NULL) != SEC_E_OK)
        {
            closesocket(s.sock);
            WSACleanup();
            return -1;
        }
    }

    s.received = s.used = s.available = 0;
    s.decrypted = NULL;
    // perform tls handshake
    // 1) call InitializeSecurityContext to create/update schannel context
    // 2) when it returns SEC_E_OK - tls handshake completed
    // 3) when it returns SEC_I_INCOMPLETE_CREDENTIALS - server requests client certificate (not supported here)
    // 4) when it returns SEC_I_CONTINUE_NEEDED - send token to server and read data
    // 5) when it returns SEC_E_INCOMPLETE_MESSAGE - need to read more data from server
    // 6) otherwise read data from server and go to step 1

    CtxtHandle* context = NULL;
    int result = 0;
    for (;;) {
        SecBuffer inbuffers[2] = { 0 };
        inbuffers[0].BufferType = SECBUFFER_TOKEN;
        inbuffers[0].pvBuffer = s.incoming;
        inbuffers[0].cbBuffer = s.received;
        inbuffers[1].BufferType = SECBUFFER_EMPTY;

        SecBuffer outbuffers[1] = { 0 };
        outbuffers[0].BufferType = SECBUFFER_TOKEN;

        SecBufferDesc indesc = { SECBUFFER_VERSION, ARRAYSIZE(inbuffers), inbuffers };
        SecBufferDesc outdesc = { SECBUFFER_VERSION, ARRAYSIZE(outbuffers), outbuffers };

        DWORD flags = ISC_REQ_USE_SUPPLIED_CREDS | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM;
        SECURITY_STATUS sec = InitializeSecurityContextA(
            &s.handle,
            context,
            context ? NULL : (SEC_CHAR*)hostname,
            flags,
            0,
            0,
            context ? &indesc : NULL,
            0,
            context ? NULL : &s.context,
            &outdesc,
            &flags,
            NULL);
            if (sec == SEC_E_INVALID_TOKEN) std::cout << "failed\n";
        
    }
}

This is the code I'm running, from https://gist.github.com/mmozeiko/c0dfcc8fec527a90a02145d2cc0bfb6d here. The error code in question is "SEC_E_INVALID_TOKEN" The same error does persist with or without the full code. It only happens on some requests, to some sites. Sending the same request several times, sometimes it has this error, other times it doesn't, and only on this site that I've found so far. What does it mean, and how can I fix it? I don't know what "token" is being referred to, because I don't even see where anything called a token is passed.

Upvotes: 0

Views: 299

Answers (0)

Related Questions