C++ Windows Winsock SChannel – AcquireCredentialsHandleW failing – due to UNISP_NAME or SChannel?

huangapple go评论66阅读模式
英文:

C++ Windows Winsock SChannel - AcquireCredentialsHandleW failing - due to UNISP_NAME or SChannel?

问题

我正在尝试在 Windows 中使用 winsock、schannel、security 等,在 C++ x64 unicode 中实现 SSL 握手。示例主机是 google.com。

我创建了一个 SOCKET,并且可以通过 WSAConnectByNameW 连接。

我设置了我的 SCHANNEL 参数如下:

SCHANNEL_CRED *cred = new SCHANNEL_CRED;
cred->dwVersion = SCHANNEL_CRED_VERSION;
cred->dwFlags = SCH_USE_STRONG_CRYPTO | SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS;
cred->grbitEnabledProtocols = SP_PROT_TLS1_2;

我想要使用 AcquireCredentialsHandleW(传递 UNISP_NAME)获取句柄:

SECURITY_STATUS secstatus = AcquireCredentialsHandleW(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &handle, NULL);

由于不兼容的数据类型,这会失败:

""const wchar_t *"" --> ""LPWSTR"""

顺便说一下,这里的 Handle 只是一个 CredHandle。

我正在使用 Unicode,所以我认为我可以使用 UNISP_NAME,因为它是一个以 0 结尾的字符串。
我尝试将字符串转换为 LPWSTR。这只是指向以 0 结尾字符串的指针,对吧?

std::wstring service = L"Microsoft Unified Security Protocol Provider";
LPWSTR servicePtr = &service[0];

然后将其传递给函数:

SECURITY_STATUS secstatus = AcquireCredentialsHandleW(NULL, servicePtr, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &handle, NULL);

但似乎不起作用。我不明白。我的问题是什么?
为什么我无法获取句柄?为什么函数(AcquireCredentialsHandleW)即使在正确的编码中也不接受其自己的预编码参数?

提前感谢。

PS:我想尽量不使用 OpenSSL 或 Curl 进行尝试 ^^

尝试切换到多字节编码。相同的问题,但不是针对 wchar,而是 char。
尝试将字符串转换为指针
尝试使用不同编码的 schannel 参数。

英文:

I'm trying to implement an SSL handshake in C++ x64 unicode in Windows using winsock, schannel, security etc. Example host is google.com.

I created a SOCKET and could connect via WSAConnectByNameW.

I'm setting my SCHANNEL parameters as followed:

SCHANNEL_CRED *cred = new SCHANNEL_CRED;
cred->dwVersion = SCHANNEL_CRED_VERSION;
cred->dwFlags = SCH_USE_STRONG_CRYPTO | SCH_CRED_AUTO_CRED_VALIDATION| SCH_CRED_NO_DEFAULT_CREDS;
cred->grbitEnabledProtocols = SP_PROT_TLS1_2;

I want to get the handle using AcquireCredentialsHandleW (passing UNISP_NAME):

SECURITY_STATUS secstatus = AcquireCredentialsHandleW(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &handle, NULL);

Which fails for some reason due to incompatible data types:

> ""const wchar_t *"" --> ""LPWSTR""

Btw. Handle is just a CredHandle here.

I'm using unicode so I thought I could use UNISP_NAME since it's a 0 terminated string.
I tried converting the string into an LPWSTR. Which is just an pointer to a 0 terminated string, right?

std::wstring service = L"Microsoft Unified Security Protocol Provider";
LPWSTR servicePtr = &service[0];

And pass it to the function:

SECURITY_STATUS secstatus = AcquireCredentialsHandleW(NULL, servicePtr, SECPKG_CRED_OUTBOUND, NULL, &cred, NULL, NULL, &handle, NULL);

But it doesn't seem to work. I don't get it. What's my problem here?
Why can't I get the handle? Why does the function (AcquireCredentialsHandleW) does not accept its own pre-coded parameters even in the correct encoding?

Thanks in advance.

PS.: I want to try it without openssl or curl as far as I can make it ^^

Tried switching to multibyte. Same problem but not for wchar but chars.
Tried converting the string to a pointer
tried switching schannel parameter with differently encoded parameter.

答案1

得分: 0

AcquireCredentialsHandle()的第二个参数期望一个指向非const字符串的指针(为什么是非const?谁知道)。

UNISP_NAME只是一个字符串字面量的#define

#define UNISP_NAME_A    "Microsoft Unified Security Protocol Provider"
#define UNISP_NAME_W    L"Microsoft Unified Security Protocol Provider"

#ifdef UNICODE

#define UNISP_NAME  UNISP_NAME_W
...

#else

#define UNISP_NAME  UNISP_NAME_A
...

#endif

在C++中,字符串字面量是const字符串(在这种情况下是const wchar_t[],它退化const wchar_t*)。

所以,在C++中,你需要去掉const,例如:

AcquireCredentialsHandleW(..., const_cast<LPWSTR>(UNISP_NAME), ...);

或者,你可以使用字符串字面量来初始化一个非const字符缓冲区,例如:

WCHAR szPackage[] = UNISP_NAME;
AcquireCredentialsHandleW(..., szPackage, ...);

在C++11及更高版本中,你的wstring::operator[]方法应该能够正常工作,因为std::wstring的内部内存缓冲区保证是以空字符结尾的,例如:

std::wstring package = UNISP_NAME_W;
AcquireCredentialsHandleW(..., &package[0], ...);

或者,你可以从wstring::c_str()返回的指针中去掉const,例如:

std::wstring package = UNISP_NAME_W;
AcquireCredentialsHandleW(..., const_cast<LPWSTR>(package.c_str()), ...);

或者,在C++17及更高版本中,wstring::data()有一个重载,可以返回一个非const指针,例如:

std::wstring package = UNISP_NAME_W;
AcquireCredentialsHandleW(..., package.data(), ...);
英文:

The second parameter of AcquireCredentialsHandle() expects a pointer to a non-const string (why non-const? who knows).

UNISP_NAME is just a #define for a string literal:

#define UNISP_NAME_A    &quot;Microsoft Unified Security Protocol Provider&quot;
#define UNISP_NAME_W    L&quot;Microsoft Unified Security Protocol Provider&quot;

#ifdef UNICODE

#define UNISP_NAME  UNISP_NAME_W
...

#else

#define UNISP_NAME  UNISP_NAME_A
...

#endif

In C++, a string literal is a const string (in this case, a const wchar_t[], which decays into a const wchar_t*).

So, you will have to cast away the const in C++, eg:

AcquireCredentialsHandleW(..., const_cast&lt;LPWSTR&gt;(UNISP_NAME), ...);

Alternatively, you can use a string literal to initialize a non-const character buffer, eg:

WCHAR szPackage[] = UNISP_NAME;
AcquireCredentialsHandleW(..., szPackage, ...);

Your wstring::operator[] approach should work fine in C++11 and later, where the internal memory buffer of std::wstring is guaranteed to be null-terminated, eg:

std::wstring package = UNISP_NAME_W;
AcquireCredentialsHandleW(..., &amp;package[0], ...);

Or, you can cast away the const from the pointer returned by wstring::c_str(), eg:

std::wstring package = UNISP_NAME_W;
AcquireCredentialsHandleW(..., const_cast&lt;LPWSTR&gt;(package.c_str()), ...);

Or, in C++17 and later, wstring::data() has an overload to return a non-const pointer, eg:

std::wstring package = UNISP_NAME_W;
AcquireCredentialsHandleW(..., package.data(), ...);

huangapple
  • 本文由 发表于 2023年5月24日 22:14:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76324518.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定