From: Benoît Legat <benoit.legat@gmail.com> --- dlls/secur32/schannel.c | 191 ++++++++++++++------------------- dlls/secur32/schannel_gnutls.c | 54 +++++----- 2 files changed, 107 insertions(+), 138 deletions(-) diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c index 7d31713e7a5..261d0606244 100644 --- a/dlls/secur32/schannel.c +++ b/dlls/secur32/schannel.c @@ -514,6 +514,80 @@ static WCHAR *get_key_container_path(const CERT_CONTEXT *ctx) } #define MAX_LEAD_BYTES 8 + +static void reverse_bytes(BYTE *buf, ULONG len) +{ + BYTE tmp; + ULONG i; + for (i = 0; i < len / 2; i++) + { + tmp = buf[i]; + buf[i] = buf[len - i - 1]; + buf[len - i - 1] = tmp; + } +} + +/* Convert CAPI PRIVATEKEYBLOB (little-endian) to BCRYPT_RSAKEY_BLOB (big-endian) */ +static BYTE *convert_capi_to_bcrypt(const BYTE *capi_blob, DWORD capi_size, DWORD *out_size) +{ + const BLOBHEADER *blob_hdr = (const BLOBHEADER *)capi_blob; + const RSAPUBKEY *rsa_hdr = (const RSAPUBKEY *)(blob_hdr + 1); + BCRYPT_RSAKEY_BLOB *hdr; + DWORD bitlen, modlen, half, bcrypt_size; + const BYTE *src; + BYTE *buf, *dst; + + if (capi_size < sizeof(BLOBHEADER) + sizeof(RSAPUBKEY)) return NULL; + + bitlen = rsa_hdr->bitlen; + modlen = bitlen / 8; + half = bitlen / 16; + + bcrypt_size = sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(rsa_hdr->pubexp) + modlen * 2 + half * 5; + if (!(buf = malloc(bcrypt_size + MAX_LEAD_BYTES))) return NULL; + + hdr = (BCRYPT_RSAKEY_BLOB *)buf; + hdr->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC; + hdr->BitLength = bitlen; + hdr->cbPublicExp = sizeof(rsa_hdr->pubexp); + hdr->cbModulus = modlen; + hdr->cbPrime1 = half; + hdr->cbPrime2 = half; + + dst = buf + sizeof(*hdr); + + /* PublicExp: CAPI stores as DWORD (little-endian), BCRYPT as big-endian bytes */ + reverse_bytes((BYTE *)&rsa_hdr->pubexp, sizeof(rsa_hdr->pubexp)); + memcpy(dst, &rsa_hdr->pubexp, sizeof(rsa_hdr->pubexp)); + dst += sizeof(rsa_hdr->pubexp); + + src = (const BYTE *)(rsa_hdr + 1); + + /* Modulus */ + memcpy(dst, src, modlen); reverse_bytes(dst, modlen); + src += modlen; dst += modlen; + /* Prime1 */ + memcpy(dst, src, half); reverse_bytes(dst, half); + src += half; dst += half; + /* Prime2 */ + memcpy(dst, src, half); reverse_bytes(dst, half); + src += half; dst += half; + /* Exponent1 */ + memcpy(dst, src, half); reverse_bytes(dst, half); + src += half; dst += half; + /* Exponent2 */ + memcpy(dst, src, half); reverse_bytes(dst, half); + src += half; dst += half; + /* Coefficient */ + memcpy(dst, src, half); reverse_bytes(dst, half); + src += half; dst += half; + /* PrivateExponent */ + memcpy(dst, src, modlen); reverse_bytes(dst, modlen); + + *out_size = bcrypt_size + MAX_LEAD_BYTES; + return buf; +} + static BYTE *get_key_blob(const CERT_CONTEXT *ctx, DWORD *size) { BYTE *buf, *ret = NULL; @@ -550,121 +624,23 @@ static BYTE *get_key_blob(const CERT_CONTEXT *ctx, DWORD *size) blob_in.cbData = len; if (CryptUnprotectData(&blob_in, NULL, NULL, NULL, NULL, 0, &blob_out)) { - assert(blob_in.cbData >= blob_out.cbData); - memcpy(buf, blob_out.pbData, blob_out.cbData); + ret = convert_capi_to_bcrypt(blob_out.pbData, blob_out.cbData, size); LocalFree(blob_out.pbData); - *size = blob_out.cbData + MAX_LEAD_BYTES; - ret = buf; } } - else free(buf); + free(buf); RegCloseKey(hkey); return ret; } -static void reverse_bytes(BYTE *buf, ULONG len) -{ - BYTE tmp; - ULONG i; - for (i = 0; i < len / 2; i++) - { - tmp = buf[i]; - buf[i] = buf[len - i - 1]; - buf[len - i - 1] = tmp; - } -} - -/* Convert BCRYPT_RSAKEY_BLOB (big-endian) to CAPI PRIVATEKEYBLOB (little-endian) */ -static BYTE *convert_bcrypt_to_capi(const BYTE *bcrypt_blob, DWORD bcrypt_size, DWORD *out_size) -{ - const BCRYPT_RSAKEY_BLOB *hdr = (const BCRYPT_RSAKEY_BLOB *)bcrypt_blob; - DWORD bitlen, half, modlen, capi_size; - BLOBHEADER *blob_hdr; - RSAPUBKEY *rsa_hdr; - const BYTE *src; - BYTE *buf, *dst; - - if (bcrypt_size < sizeof(*hdr)) return NULL; - if (hdr->Magic != BCRYPT_RSAFULLPRIVATE_MAGIC) - { - TRACE("unexpected magic %#lx\n", (unsigned long)hdr->Magic); - return NULL; - } - - bitlen = hdr->BitLength; - modlen = bitlen / 8; - half = bitlen / 16; - - /* CAPI blob: BLOBHEADER + RSAPUBKEY + modulus + p + q + e1 + e2 + coeff + d */ - capi_size = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) + modlen + 5 * half + modlen; - - if (!(buf = malloc(capi_size + MAX_LEAD_BYTES))) return NULL; - - /* BLOBHEADER */ - blob_hdr = (BLOBHEADER *)buf; - blob_hdr->bType = 0x07; /* PRIVATEKEYBLOB */ - blob_hdr->bVersion = 0x02; /* CUR_BLOB_VERSION */ - blob_hdr->reserved = 0; - blob_hdr->aiKeyAlg = 0xa400; /* CALG_RSA_KEYX */ - - /* RSAPUBKEY */ - rsa_hdr = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER)); - rsa_hdr->magic = 0x32415352; /* "RSA2" */ - rsa_hdr->bitlen = bitlen; - /* public exponent: BCRYPT stores big-endian variable-length, CAPI stores as DWORD */ - rsa_hdr->pubexp = 0; - src = bcrypt_blob + sizeof(*hdr); - if (hdr->cbPublicExp <= 4) - { - DWORD i; - for (i = 0; i < hdr->cbPublicExp; i++) - rsa_hdr->pubexp = (rsa_hdr->pubexp << 8) | src[i]; - } - - /* Skip past public exponent in BCRYPT blob */ - src += hdr->cbPublicExp; - - dst = (BYTE *)(rsa_hdr + 1); - - /* Modulus: copy and reverse (big-endian to little-endian) */ - memcpy(dst, src, modlen); reverse_bytes(dst, modlen); - src += hdr->cbModulus; dst += modlen; - - /* Prime1 (p) */ - memcpy(dst, src, half); reverse_bytes(dst, half); - src += hdr->cbPrime1; dst += half; - - /* Prime2 (q) */ - memcpy(dst, src, half); reverse_bytes(dst, half); - src += hdr->cbPrime2; dst += half; - - /* Exponent1 (dp) */ - memcpy(dst, src, half); reverse_bytes(dst, half); - src += hdr->cbPrime1; dst += half; - - /* Exponent2 (dq) */ - memcpy(dst, src, half); reverse_bytes(dst, half); - src += hdr->cbPrime2; dst += half; - - /* Coefficient (InverseQ) */ - memcpy(dst, src, half); reverse_bytes(dst, half); - src += hdr->cbPrime1; dst += half; - - /* PrivateExponent (d) */ - memcpy(dst, src, modlen); reverse_bytes(dst, modlen); - - *out_size = capi_size + MAX_LEAD_BYTES; - return buf; -} - static BYTE *get_key_blob_ncrypt(const CERT_CONTEXT *ctx, DWORD *size) { CERT_KEY_CONTEXT keyctx; DWORD ctx_size = sizeof(keyctx); NCRYPT_KEY_HANDLE key; DWORD blob_size; - BYTE *bcrypt_buf, *capi_buf; + BYTE *buf; SECURITY_STATUS status; if (!CertGetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, &keyctx, &ctx_size)) @@ -681,21 +657,18 @@ static BYTE *get_key_blob_ncrypt(const CERT_CONTEXT *ctx, DWORD *size) return NULL; } - if (!(bcrypt_buf = malloc(blob_size))) return NULL; + if (!(buf = malloc(blob_size + MAX_LEAD_BYTES))) return NULL; - status = NCryptExportKey(key, 0, BCRYPT_RSAFULLPRIVATE_BLOB, NULL, bcrypt_buf, blob_size, &blob_size, 0); + status = NCryptExportKey(key, 0, BCRYPT_RSAFULLPRIVATE_BLOB, NULL, buf, blob_size, &blob_size, 0); if (status) { TRACE("NCryptExportKey failed: %#lx\n", status); - free(bcrypt_buf); + free(buf); return NULL; } - /* Convert BCRYPT blob to CAPI PRIVATEKEYBLOB format */ - capi_buf = convert_bcrypt_to_capi(bcrypt_buf, blob_size, size); - free(bcrypt_buf); - - return capi_buf; + *size = blob_size + MAX_LEAD_BYTES; + return buf; } static SECURITY_STATUS acquire_credentials_handle(ULONG fCredentialUse, diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c index ca7e82bbbde..b95d8875d65 100644 --- a/dlls/secur32/schannel_gnutls.c +++ b/dlls/secur32/schannel_gnutls.c @@ -42,6 +42,7 @@ #include "windef.h" #include "winbase.h" #include "winternl.h" +#include "bcrypt.h" #include "sspi.h" #include "secur32_priv.h" @@ -1300,24 +1301,11 @@ static NTSTATUS schan_set_dtls_timeouts( void *args ) return SEC_E_OK; } -static inline void reverse_bytes(BYTE *buf, ULONG len) -{ - BYTE tmp; - ULONG i; - for (i = 0; i < len / 2; i++) - { - tmp = buf[i]; - buf[i] = buf[len - i - 1]; - buf[len - i - 1] = tmp; - } -} - static ULONG set_component(gnutls_datum_t *comp, BYTE *data, ULONG len, ULONG *buflen) { comp->data = data; comp->size = len; - reverse_bytes(comp->data, comp->size); - if (comp->data[0] & 0x80) /* add leading 0 byte if most significant bit is set */ + if (comp->size > 0 && comp->data[0] & 0x80) /* add leading 0 byte if most significant bit is set */ { memmove(comp->data + 1, comp->data, *buflen); comp->data[0] = 0; @@ -1327,32 +1315,40 @@ static ULONG set_component(gnutls_datum_t *comp, BYTE *data, ULONG len, ULONG *b return comp->size; } +/* BCRYPT_RSAKEY_BLOB layout: already big-endian, matching GnuTLS expectations. */ static gnutls_x509_privkey_t get_x509_key(ULONG key_size, const BYTE *key_blob) { gnutls_privkey_t key = NULL; gnutls_x509_privkey_t x509key = NULL; gnutls_datum_t m, e, d, p, q, u, e1, e2; + const BCRYPT_RSAKEY_BLOB *hdr = (const BCRYPT_RSAKEY_BLOB *)key_blob; BYTE *ptr; - RSAPUBKEY *rsakey; - DWORD size = key_size; + DWORD size; int ret; - if (size < sizeof(BLOBHEADER)) return NULL; + if (key_size < sizeof(*hdr)) return NULL; + if (hdr->Magic != BCRYPT_RSAFULLPRIVATE_MAGIC) + { + TRACE("unexpected magic %#x\n", (unsigned)hdr->Magic); + return NULL; + } - rsakey = (RSAPUBKEY *)(key_blob + sizeof(BLOBHEADER)); - TRACE("RSA key bitlen %u pubexp %u\n", (unsigned)rsakey->bitlen, (unsigned)rsakey->pubexp); + TRACE("BCRYPT RSA key bitlen %u cbExp %u cbMod %u cbP1 %u cbP2 %u\n", + (unsigned)hdr->BitLength, (unsigned)hdr->cbPublicExp, (unsigned)hdr->cbModulus, + (unsigned)hdr->cbPrime1, (unsigned)hdr->cbPrime2); - size -= sizeof(BLOBHEADER) + FIELD_OFFSET(RSAPUBKEY, pubexp); - set_component(&e, (BYTE *)&rsakey->pubexp, sizeof(rsakey->pubexp), &size); + size = key_size - sizeof(*hdr); + ptr = (BYTE *)(hdr + 1); - ptr = (BYTE *)(rsakey + 1); - ptr += set_component(&m, ptr, rsakey->bitlen / 8, &size); - ptr += set_component(&p, ptr, rsakey->bitlen / 16, &size); - ptr += set_component(&q, ptr, rsakey->bitlen / 16, &size); - ptr += set_component(&e1, ptr, rsakey->bitlen / 16, &size); - ptr += set_component(&e2, ptr, rsakey->bitlen / 16, &size); - ptr += set_component(&u, ptr, rsakey->bitlen / 16, &size); - ptr += set_component(&d, ptr, rsakey->bitlen / 8, &size); + /* BCRYPT blob: PublicExp, Modulus, Prime1, Prime2, Exponent1, Exponent2, Coefficient, PrivateExponent */ + ptr += set_component(&e, ptr, hdr->cbPublicExp, &size); + ptr += set_component(&m, ptr, hdr->cbModulus, &size); + ptr += set_component(&p, ptr, hdr->cbPrime1, &size); + ptr += set_component(&q, ptr, hdr->cbPrime2, &size); + ptr += set_component(&e1, ptr, hdr->cbPrime1, &size); + ptr += set_component(&e2, ptr, hdr->cbPrime2, &size); + ptr += set_component(&u, ptr, hdr->cbPrime1, &size); + ptr += set_component(&d, ptr, hdr->cbModulus, &size); if ((ret = pgnutls_privkey_init(&key)) < 0) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10561