为什么我的 Schannel 服务器挂在 `recv` 上?

问题描述

所以我正在将 Schannel 服务器写入 IOS Gmail 客户端应用程序 - IMAP 服务器。

我正在强制使用 TLS1.0(尝试使用 TLS1.0to1.3 - 1.3 似乎可以通过 algo_mismatch 保释,但其他人也这样做,我也尝试使用 SSL3.0,但读到 gmail 不支持) .

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

我需要澄清 - 它在第一次成功结束时进入循环(AcceptSecurityContextSEC_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,* 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,InBuff->pBuffers[0].pvBuffer = *d,0);
        switch (acceptctxsecstat = diagnose(AcceptSecurityContext,&hCred,pctx,InBuff,ctxflags,&ctx,OutBuff,&attrs,&nocare))
        {
        case SEC_I_CONTINUE_NEEDED:
        case_continue_needed:
            //,server,Security_NATIVE_DREP,//diagnose(CompleteAuthToken,OutBuff),//OutBuff->pBuffers[0].cbBuffer = check_last_error_int(recv,0),check_last_error_int(send,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,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,SECPKG_ATTR_STREAM_SIZES,&ctxSizes);
    free(d);
    return (struct performhandshake) { ctx,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,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,CERT_FIND_SUBJECT_STR_A,// 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,UNISP_NAME,SECPKG_CRED_BOTH,&(SCHANNEL_CRED){.dwVersion = SCHANNEL_CRED_VERSION,.hRootStore = hMyCertStore,.cCreds = 1,.paCred = (PCCERT_CONTEXT[]){ aCertContext },.grbitEnabledProtocols = SP_PROT_TLS1_0_SERVER },& hCred,& nocare);

    SecInvalidateHandle(&reshandshake.ctx) reshandshake = performhandshake(reshandshake.ctx,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,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,line) char desc[]; {BOOL bLowMemoryIndicator = FALSE; int error = WSAGetLastError(); error ? EnterCriticalSection(&crit),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__),__LINE__)

static struct check_last_error_internal_handle {
    SOCKET socket;
    BOOL bLowMemoryIndicator;
} check_last_error_internal_handle(in,line) char desc[]; SOCKET in; {BOOL bLowMemoryIndicator = FALSE; int error = WSAGetLastError(); error ? EnterCriticalSection(&crit),LeaveCriticalSection(&crit) : 0; return (struct check_last_error_internal_handle) { in,bLowMemoryIndicator }; }

#define check_last_error_handle(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,SOL_SOCKET,SO_RCVTIMEO,(DWORD[]) { 100 },sizeof(DWORD)),//check_last_error_int(setsockopt,SO_SNDTIMEO,check_last_error_int(bind,addrinfo->ai_addr,addrinfo->ai_addrlen),check_last_error_int(listen,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,bLowMemoryIndicator };
}

main() {
    WSADATA wsadat; WSAStartup(MAKEWORD(2,conn);

    return;
}

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

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)