0

所以我正在编写一个 Schannel 服务器到 IOS Gmail 客户端应用程序 - IMAP 服务器。

我正在强制使用 TLS1.0(尝试使用 TLS1.0to1.3 - 1.3 似乎可以使用 algo_mismatch 但其他的也一样,我也尝试使用 SSL3.0,但阅读 gmail 不支持。

目前我无法克服似乎挂在recv. 我不知道我做错了什么 - 我还在我的(客户端设备 - IOS)上安装了证书。

我需要澄清 - 它第一次进入循环,成功结束(AcceptSecurityContextwith SEC_I_CONTINUE_NEEDED),但在send(我还检查了它的结果与cbBuffer大小匹配,所以它必须没问题)之后它会挂起recv

这是握手部分:

static struct performhandshake {
    CtxtHandle ctx; CredHandle hCred; SOCKET sock; SecPkgContext_StreamSizes ctxSizes; BOOL bLowMemoryIndicator;
} performhandshake(ctx, hCred, sock) CtxtHandle ctx; CredHandle hCred; SOCKET sock; {
    SecPkgContext_StreamSizes ctxSizes;
    struct diagose_internal diagose_internal_res; BOOL bLowMemoryIndicator = FALSE; SECURITY_STATUS acceptctxsecstat;
    CtxtHandle* pctx = SecIsValidHandle(&ctx) ? &ctx : 0;
    SecBufferDesc buff = { .ulVersion = SECBUFFER_VERSION,1,(SecBuffer[]) { [0] = {.BufferType = SECBUFFER_TOKEN} } }, * LastRecieved,
        outbuff = { .ulVersion = SECBUFFER_VERSION,1,(SecBuffer[]) { [0] = {.BufferType = SECBUFFER_TOKEN} } },
        * InBuff = &outbuff,
        * OutBuff = &buff; DWORD attrs; TimeStamp nocare;
    char(*d)[USHRT_MAX] = malloc(sizeof * d);
    //OutBuff->pBuffers[0].cbBuffer = check_last_error_int(recv, sock, OutBuff->pBuffers[0].pvBuffer = *d, sizeof * d, 0);
    do {
        InBuff->pBuffers[0].cbBuffer = check_last_error_int(recv, sock, InBuff->pBuffers[0].pvBuffer = *d, sizeof * d, 0);
        switch (acceptctxsecstat = diagnose(AcceptSecurityContext, &hCred, pctx, InBuff, ctxflags, 0, &ctx, OutBuff, &attrs, &nocare))
        {
        case SEC_I_CONTINUE_NEEDED:
        case_continue_needed:
            //, server, ctxflags, 0, SECURITY_NATIVE_DREP,
            //diagnose(CompleteAuthToken, &ctx, OutBuff),
            //OutBuff->pBuffers[0].cbBuffer = check_last_error_int(recv, sock, OutBuff->pBuffers[0].pvBuffer = *d, sizeof * d, 0),
            check_last_error_int(send, sock, OutBuff->pBuffers[0].pvBuffer, OutBuff->pBuffers[0].cbBuffer, 0);
            FreeContextBuffer(OutBuff->pBuffers[0].pvBuffer);
            LastRecieved = OutBuff; swap_ptr64(InBuff, OutBuff);
            pctx = &ctx;
            break;
        case SEC_I_COMPLETE_NEEDED:
        case SEC_I_COMPLETE_AND_CONTINUE:
            diagnose(CompleteAuthToken, pctx, OutBuff);
            switch (acceptctxsecstat) {
            case SEC_I_COMPLETE_NEEDED:
                goto end;
            case SEC_I_COMPLETE_AND_CONTINUE:
                goto case_continue_needed;
            }
        default: goto end;
        }
    } while (/*OutBuff->pBuffers[0].cbBuffer != SOCKET_ERROR && OutBuff->pBuffers[0].cbBuffer*/true);
end:
    diagnose(QueryContextAttributes, &ctx, SECPKG_ATTR_STREAM_SIZES, &ctxSizes);
    free(d);
    return (struct performhandshake) { ctx, hCred, sock, ctxSizes, bLowMemoryIndicator };
}

这是我的主要功能:

main() {
    WSADATA wsadat; WSAStartup(MAKEWORD(2, 2), &wsadat), getaddrinfo("<local-ip>", "993", (struct addrinfo[])
    { {.ai_family = AF_INET, .ai_socktype = SOCK_STREAM, .ai_protocol = IPPROTO_TCP, .ai_flags = AI_PASSIVE}
    }, & addrinfo);

    InitializeCriticalSection(&crit);

    HCERTSTORE hMyCertStore = NULL;
    PCCERT_CONTEXT aCertContext = NULL;

    //-------------------------------------------------------
    // Open the My store, also called the personal store.
    // This call to CertOpenStore opens the Local_Machine My 
    // store as opposed to the Current_User's My store.

    hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
        X509_ASN_ENCODING,
        0,
        CERT_SYSTEM_STORE_CURRENT_USER,
        L"MY");

    if (hMyCertStore == NULL)
        printf("Error opening MY store for server.\n");
    //-------------------------------------------------------
    // Search for a certificate with some specified
    // string in it. This example attempts to find
    // a certificate with the string "example server" in
    // its subject string. Substitute an appropriate string
    // to find a certificate for a specific user.

    aCertContext = CertFindCertificateInStore(hMyCertStore,
        X509_ASN_ENCODING,
        0,
        CERT_FIND_SUBJECT_STR_A,
        server, // use appropriate subject name
        NULL
    );

    if (aCertContext == NULL)
        printf("Error retrieving server certificate.");

    CertCloseStore(hMyCertStore, 0);

    char buff[USHRT_MAX];

    SOCKET conn = beginconn(&buff);

    struct performhandshake reshandshake;

    CredHandle hCred; TimeStamp nocare; struct diagose_internal diagose_internal_res; BOOL bLowMemoryIndicator = FALSE;

    diagnose(AcquireCredentialsHandle, 0, UNISP_NAME, SECPKG_CRED_BOTH, 0, &(SCHANNEL_CRED){.dwVersion = SCHANNEL_CRED_VERSION, .hRootStore = hMyCertStore,
        .cCreds = 1, .paCred = (PCCERT_CONTEXT[]){ aCertContext }, .grbitEnabledProtocols = SP_PROT_TLS1_0_SERVER }, 0, 0, & hCred, & nocare);

    SecInvalidateHandle(&reshandshake.ctx) reshandshake = performhandshake(reshandshake.ctx, hCred, conn);

    return;
}

这是整个片段供参考:

#undef UNICODE
#include <winsock2.h> 

#include <stdio.h>
#include <stdbool.h>

#define SECURITY_WIN32

#include <Security.h>
#include <Schnlsp.h>


const char server[] = "<cert-name>";

#define errprintf(...) (printf(__VA_ARGS__))

#define ctxflags (ASC_REQ_ALLOCATE_MEMORY|ASC_REQ_CONFIDENTIALITY)

#define swap(x,y)(x ^= y,y ^= x,x ^= y)

#define swap_ptr64(x,y)swap(*(ULONG64 *)&x, *(ULONG64 *)&y)

struct addrinfo* addrinfo;

static CRITICAL_SECTION crit;

static struct diagose_internal {
    SECURITY_STATUS secstat;
    BOOL bLowMemoryIndicator;
} diagose_internal(in, desc, line) char desc[]; SECURITY_STATUS in; {BOOL bLowMemoryIndicator = FALSE; in & 0x80000000 ? EnterCriticalSection(&crit),
errprintf("%d - %s - %lx\n", line, desc, in), bLowMemoryIndicator = SEC_E_INSUFFICIENT_MEMORY == in, LeaveCriticalSection(&crit) : 0; return (struct diagose_internal) { in, bLowMemoryIndicator }; }

#define diagnose(x, ...) (diagose_internal_res=diagose_internal(x(__VA_ARGS__),#x,__LINE__), bLowMemoryIndicator=bLowMemoryIndicator||diagose_internal_res.bLowMemoryIndicator, diagose_internal_res.secstat)

static BOOL check_last_error_internal_int(in, desc, line) char desc[]; {BOOL bLowMemoryIndicator = FALSE; int error = WSAGetLastError(); error ? EnterCriticalSection(&crit),
errprintf("%d - %s - %lx\n", line, desc, error), bLowMemoryIndicator = error == WSA_NOT_ENOUGH_MEMORY, //|| error == WSA_QOS_TRAFFIC_CTRL_ERROR,
LeaveCriticalSection(&crit) : 0; return in; }

#define check_last_error_int(x, ...) check_last_error_internal_int(x(__VA_ARGS__),#x,__LINE__)

static struct check_last_error_internal_handle {
    SOCKET socket;
    BOOL bLowMemoryIndicator;
} check_last_error_internal_handle(in, desc, line) char desc[]; SOCKET in; {BOOL bLowMemoryIndicator = FALSE; int error = WSAGetLastError(); error ? EnterCriticalSection(&crit),
errprintf("%d - %s - %lx\n", line, desc, error), bLowMemoryIndicator = error == WSA_NOT_ENOUGH_MEMORY, //|| error == WSA_QOS_TRAFFIC_CTRL_ERROR,
LeaveCriticalSection(&crit) : 0; return (struct check_last_error_internal_handle) { in, bLowMemoryIndicator }; }

#define check_last_error_handle(x, ...) check_last_error_internal_int(x(__VA_ARGS__),#x,__LINE__)

static SOCKET beginconn() {
    SOCKET sock = check_last_error_handle(socket, addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
    //check_last_error_int(setsockopt, sock, SOL_SOCKET, SO_RCVTIMEO, (DWORD[]) { 100 }, sizeof(DWORD)),
        //check_last_error_int(setsockopt, sock, SOL_SOCKET, SO_SNDTIMEO, (DWORD[]) { 100 }, sizeof(DWORD)),
    check_last_error_int(bind, sock, addrinfo->ai_addr, addrinfo->ai_addrlen),
        check_last_error_int(listen, sock, SOMAXCONN);
    SOCKET finalsock = accept(sock, NULL, NULL);
    closesocket(sock);
    return finalsock;
}

static struct performhandshake {
    CtxtHandle ctx; CredHandle hCred; SOCKET sock; SecPkgContext_StreamSizes ctxSizes; BOOL bLowMemoryIndicator;
} performhandshake(ctx, hCred, sock) CtxtHandle ctx; CredHandle hCred; SOCKET sock; {
    SecPkgContext_StreamSizes ctxSizes;
    struct diagose_internal diagose_internal_res; BOOL bLowMemoryIndicator = FALSE; SECURITY_STATUS acceptctxsecstat;
    CtxtHandle* pctx = SecIsValidHandle(&ctx) ? &ctx : 0;
    SecBufferDesc buff = { .ulVersion = SECBUFFER_VERSION,1,(SecBuffer[]) { [0] = {.BufferType = SECBUFFER_TOKEN} } }, * LastRecieved,
        outbuff = { .ulVersion = SECBUFFER_VERSION,1,(SecBuffer[]) { [0] = {.BufferType = SECBUFFER_TOKEN} } },
        * InBuff = &outbuff,
        * OutBuff = &buff; DWORD attrs; TimeStamp nocare;
    char(*d)[USHRT_MAX] = malloc(sizeof * d);
    //OutBuff->pBuffers[0].cbBuffer = check_last_error_int(recv, sock, OutBuff->pBuffers[0].pvBuffer = *d, sizeof * d, 0);
    do {
        InBuff->pBuffers[0].cbBuffer = check_last_error_int(recv, sock, InBuff->pBuffers[0].pvBuffer = *d, sizeof * d, 0);
        switch (acceptctxsecstat = diagnose(AcceptSecurityContext, &hCred, pctx, InBuff, ctxflags, 0, &ctx, OutBuff, &attrs, &nocare))
        {
        case SEC_I_CONTINUE_NEEDED:
        case_continue_needed:
            //, server, ctxflags, 0, SECURITY_NATIVE_DREP,
            //diagnose(CompleteAuthToken, &ctx, OutBuff),
            //OutBuff->pBuffers[0].cbBuffer = check_last_error_int(recv, sock, OutBuff->pBuffers[0].pvBuffer = *d, sizeof * d, 0),
            check_last_error_int(send, sock, OutBuff->pBuffers[0].pvBuffer, OutBuff->pBuffers[0].cbBuffer, 0);
            FreeContextBuffer(OutBuff->pBuffers[0].pvBuffer);
            LastRecieved = OutBuff; swap_ptr64(InBuff, OutBuff);
            pctx = &ctx;
            break;
        case SEC_I_COMPLETE_NEEDED:
        case SEC_I_COMPLETE_AND_CONTINUE:
            diagnose(CompleteAuthToken, pctx, OutBuff);
            switch (acceptctxsecstat) {
            case SEC_I_COMPLETE_NEEDED:
                goto end;
            case SEC_I_COMPLETE_AND_CONTINUE:
                goto case_continue_needed;
            }
        default: goto end;
        }
    } while (/*OutBuff->pBuffers[0].cbBuffer != SOCKET_ERROR && OutBuff->pBuffers[0].cbBuffer*/true);
end:
    diagnose(QueryContextAttributes, &ctx, SECPKG_ATTR_STREAM_SIZES, &ctxSizes);
    free(d);
    return (struct performhandshake) { ctx, hCred, sock, ctxSizes, bLowMemoryIndicator };
}

main() {
    WSADATA wsadat; WSAStartup(MAKEWORD(2, 2), &wsadat), getaddrinfo("<local-ip>", "993", (struct addrinfo[])
    { {.ai_family = AF_INET, .ai_socktype = SOCK_STREAM, .ai_protocol = IPPROTO_TCP, .ai_flags = AI_PASSIVE}
    }, & addrinfo);

    InitializeCriticalSection(&crit);

    HCERTSTORE hMyCertStore = NULL;
    PCCERT_CONTEXT aCertContext = NULL;

    //-------------------------------------------------------
    // Open the My store, also called the personal store.
    // This call to CertOpenStore opens the Local_Machine My 
    // store as opposed to the Current_User's My store.

    hMyCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
        X509_ASN_ENCODING,
        0,
        CERT_SYSTEM_STORE_CURRENT_USER,
        L"MY");

    if (hMyCertStore == NULL)
        printf("Error opening MY store for server.\n");
    //-------------------------------------------------------
    // Search for a certificate with some specified
    // string in it. This example attempts to find
    // a certificate with the string "example server" in
    // its subject string. Substitute an appropriate string
    // to find a certificate for a specific user.

    aCertContext = CertFindCertificateInStore(hMyCertStore,
        X509_ASN_ENCODING,
        0,
        CERT_FIND_SUBJECT_STR_A,
        server, // use appropriate subject name
        NULL
    );

    if (aCertContext == NULL)
        printf("Error retrieving server certificate.");

    CertCloseStore(hMyCertStore, 0);

    char buff[USHRT_MAX];

    SOCKET conn = beginconn(&buff);

    struct performhandshake reshandshake;

    CredHandle hCred; TimeStamp nocare; struct diagose_internal diagose_internal_res; BOOL bLowMemoryIndicator = FALSE;

    diagnose(AcquireCredentialsHandle, 0, UNISP_NAME, SECPKG_CRED_BOTH, 0, &(SCHANNEL_CRED){.dwVersion = SCHANNEL_CRED_VERSION, .hRootStore = hMyCertStore,
        .cCreds = 1, .paCred = (PCCERT_CONTEXT[]){ aCertContext }, .grbitEnabledProtocols = SP_PROT_TLS1_0_SERVER }, 0, 0, & hCred, & nocare);

    SecInvalidateHandle(&reshandshake.ctx) reshandshake = performhandshake(reshandshake.ctx, hCred, conn);

    return;
}

<local-ip><cert-name>隐藏我的真实本地 IP 和服务器/证书名称。

4

0 回答 0