Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
303
third_party/FreeRDP/winpr/libwinpr/credentials/credentials.c
vendored
Normal file
303
third_party/FreeRDP/winpr/libwinpr/credentials/credentials.c
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Credentials Management
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2025 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/cred.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include "../log.h"
|
||||
|
||||
#define TAG WINPR_TAG("Cred")
|
||||
|
||||
/*
|
||||
* Low-Level Credentials Management Functions:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731(v=vs.85).aspx#low_level_credentials_management_functions
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
static BYTE char_decode(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return (BYTE)(c - 'A');
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return (BYTE)(c - 'a' + 26);
|
||||
if (c >= '0' && c <= '9')
|
||||
return (BYTE)(c - '0' + 52);
|
||||
if (c == '#')
|
||||
return 62;
|
||||
if (c == '-')
|
||||
return 63;
|
||||
return 64;
|
||||
}
|
||||
|
||||
static BOOL cred_decode(const char* cred, size_t len, BYTE* buf)
|
||||
{
|
||||
size_t i = 0;
|
||||
const char* p = cred;
|
||||
|
||||
while (len >= 4)
|
||||
{
|
||||
BYTE c0 = char_decode(p[0]);
|
||||
if (c0 > 63)
|
||||
return FALSE;
|
||||
|
||||
BYTE c1 = char_decode(p[1]);
|
||||
if (c1 > 63)
|
||||
return FALSE;
|
||||
|
||||
BYTE c2 = char_decode(p[2]);
|
||||
if (c2 > 63)
|
||||
return FALSE;
|
||||
|
||||
BYTE c3 = char_decode(p[3]);
|
||||
if (c3 > 63)
|
||||
return FALSE;
|
||||
|
||||
buf[i + 0] = (BYTE)((c1 << 6) | c0);
|
||||
buf[i + 1] = (BYTE)((c2 << 4) | (c1 >> 2));
|
||||
buf[i + 2] = (BYTE)((c3 << 2) | (c2 >> 4));
|
||||
len -= 4;
|
||||
i += 3;
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if (len == 3)
|
||||
{
|
||||
BYTE c0 = char_decode(p[0]);
|
||||
if (c0 > 63)
|
||||
return FALSE;
|
||||
|
||||
BYTE c1 = char_decode(p[1]);
|
||||
if (c1 > 63)
|
||||
return FALSE;
|
||||
|
||||
BYTE c2 = char_decode(p[2]);
|
||||
if (c2 > 63)
|
||||
return FALSE;
|
||||
|
||||
buf[i + 0] = (BYTE)((c1 << 6) | c0);
|
||||
buf[i + 1] = (BYTE)((c2 << 4) | (c1 >> 2));
|
||||
}
|
||||
else if (len == 2)
|
||||
{
|
||||
BYTE c0 = char_decode(p[0]);
|
||||
if (c0 > 63)
|
||||
return FALSE;
|
||||
|
||||
BYTE c1 = char_decode(p[1]);
|
||||
if (c1 > 63)
|
||||
return FALSE;
|
||||
|
||||
buf[i + 0] = (BYTE)((c1 << 6) | c0);
|
||||
}
|
||||
else if (len == 1)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid string length");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static size_t cred_encode(const BYTE* bin, size_t len, char* cred, size_t credlen)
|
||||
{
|
||||
static const char encodingChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789"
|
||||
"#-";
|
||||
size_t n = 0;
|
||||
size_t offset = 0;
|
||||
while (offset < len)
|
||||
{
|
||||
if (n >= credlen)
|
||||
break;
|
||||
|
||||
cred[n++] = encodingChars[bin[offset] & 0x3f];
|
||||
BYTE x = (bin[offset] & 0xc0) >> 6;
|
||||
offset++;
|
||||
|
||||
if (offset >= len)
|
||||
{
|
||||
cred[n++] = encodingChars[x];
|
||||
break;
|
||||
}
|
||||
|
||||
if (n >= credlen)
|
||||
break;
|
||||
cred[n++] = encodingChars[((bin[offset] & 0xf) << 2) | x];
|
||||
x = (bin[offset] & 0xf0) >> 4;
|
||||
offset++;
|
||||
|
||||
if (offset >= len)
|
||||
{
|
||||
cred[n++] = encodingChars[x];
|
||||
break;
|
||||
}
|
||||
|
||||
if (n >= credlen)
|
||||
break;
|
||||
cred[n++] = encodingChars[((bin[offset] & 0x3) << 4) | x];
|
||||
|
||||
if (n >= credlen)
|
||||
break;
|
||||
cred[n++] = encodingChars[(bin[offset] & 0xfc) >> 2];
|
||||
offset++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
BOOL CredMarshalCredentialW(CRED_MARSHAL_TYPE CredType, PVOID Credential,
|
||||
LPWSTR* MarshaledCredential)
|
||||
{
|
||||
char* b = nullptr;
|
||||
if (!CredMarshalCredentialA(CredType, Credential, &b) || !b)
|
||||
return FALSE;
|
||||
|
||||
*MarshaledCredential = ConvertUtf8ToWCharAlloc(b, nullptr);
|
||||
free(b);
|
||||
return (*MarshaledCredential != nullptr);
|
||||
}
|
||||
|
||||
BOOL CredMarshalCredentialA(CRED_MARSHAL_TYPE CredType, PVOID Credential,
|
||||
LPSTR* MarshaledCredential)
|
||||
{
|
||||
CERT_CREDENTIAL_INFO* cert = Credential;
|
||||
|
||||
if (!cert || ((CredType == CertCredential) && (cert->cbSize < sizeof(CERT_CREDENTIAL_INFO))) ||
|
||||
!MarshaledCredential)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (CredType)
|
||||
{
|
||||
case CertCredential:
|
||||
{
|
||||
char buffer[3ULL + (sizeof(cert->rgbHashOfCert) * 4 / 3) + 1ULL /* rounding error */] =
|
||||
WINPR_C_ARRAY_INIT;
|
||||
|
||||
const char c = WINPR_ASSERTING_INT_CAST(char, 'A' + CredType);
|
||||
(void)_snprintf(buffer, sizeof(buffer), "@@%c", c);
|
||||
size_t len = cred_encode(cert->rgbHashOfCert, sizeof(cert->rgbHashOfCert), &buffer[3],
|
||||
sizeof(buffer) - 3);
|
||||
*MarshaledCredential = strndup(buffer, len + 3);
|
||||
return TRUE;
|
||||
}
|
||||
default:
|
||||
WLog_ERR(TAG, "unhandled type 0x%x", CredType);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CredUnmarshalCredentialW(LPCWSTR cred, PCRED_MARSHAL_TYPE CredType, PVOID* Credential)
|
||||
{
|
||||
char* str = nullptr;
|
||||
if (cred)
|
||||
str = ConvertWCharToUtf8Alloc(cred, nullptr);
|
||||
const BOOL rc = CredUnmarshalCredentialA(str, CredType, Credential);
|
||||
free(str);
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL CredUnmarshalCredentialA(LPCSTR cred, PCRED_MARSHAL_TYPE CredType, PVOID* Credential)
|
||||
{
|
||||
if (!cred)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const size_t len = strlen(cred);
|
||||
if ((len < 3) || !CredType || !Credential || (cred[0] != '@') || (cred[1] != '@'))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BYTE b = char_decode(cred[2]);
|
||||
if (!b || (b > BinaryBlobForSystem))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*CredType = (CRED_MARSHAL_TYPE)b;
|
||||
|
||||
switch (*CredType)
|
||||
{
|
||||
case CertCredential:
|
||||
{
|
||||
BYTE hash[CERT_HASH_LENGTH] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if ((len != 30) || !cred_decode(&cred[3], len - 3, hash))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CERT_CREDENTIAL_INFO* cert = calloc(1, sizeof(CERT_CREDENTIAL_INFO));
|
||||
if (!cert)
|
||||
return FALSE;
|
||||
|
||||
cert->cbSize = sizeof(CERT_CREDENTIAL_INFO);
|
||||
memcpy(cert->rgbHashOfCert, hash, sizeof(cert->rgbHashOfCert));
|
||||
*Credential = cert;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WLog_ERR(TAG, "unhandled credType 0x%x", *CredType);
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CredIsMarshaledCredentialW(LPCWSTR MarshaledCredential)
|
||||
{
|
||||
CRED_MARSHAL_TYPE t = BinaryBlobForSystem;
|
||||
void* out = nullptr;
|
||||
|
||||
BOOL ret = CredUnmarshalCredentialW(MarshaledCredential, &t, &out);
|
||||
if (out)
|
||||
CredFree(out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL CredIsMarshaledCredentialA(LPCSTR MarshaledCredential)
|
||||
{
|
||||
CRED_MARSHAL_TYPE t = BinaryBlobForSystem;
|
||||
void* out = nullptr;
|
||||
BOOL ret = CredUnmarshalCredentialA(MarshaledCredential, &t, &out);
|
||||
if (out)
|
||||
CredFree(out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
VOID CredFree(PVOID Buffer)
|
||||
{
|
||||
free(Buffer);
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
Reference in New Issue
Block a user