Alexandre Julliard : secur32: Move the memory allocation for get_session_peer_certificate() to the PE side.

Alexandre Julliard julliard at winehq.org
Mon Dec 6 16:07:58 CST 2021


Module: wine
Branch: master
Commit: bcc30639ad6c61a15ac52979805af218502648ab
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=bcc30639ad6c61a15ac52979805af218502648ab

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Dec  3 14:31:38 2021 +0100

secur32: Move the memory allocation for get_session_peer_certificate() to the PE side.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/secur32/schannel.c        | 23 ++++++++++++++++-------
 dlls/secur32/schannel_gnutls.c | 28 ++++++++++++++++++----------
 dlls/secur32/secur32_priv.h    |  8 +-------
 3 files changed, 35 insertions(+), 24 deletions(-)

diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index f9deb5d8a23..483e3285f09 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -909,28 +909,37 @@ static SECURITY_STATUS ensure_remote_cert(struct schan_context *ctx)
     HCERTSTORE store;
     PCCERT_CONTEXT cert = NULL;
     SECURITY_STATUS status;
-    struct schan_cert_list list;
+    CERT_BLOB *certs;
+    ULONG count, size = 0;
 
     if (ctx->cert) return SEC_E_OK;
     if (!(store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL)))
         return GetLastError();
 
-    if ((status = schan_funcs->get_session_peer_certificate(ctx->transport.session, &list)) == SEC_E_OK)
+    status = schan_funcs->get_session_peer_certificate(ctx->transport.session, NULL, &size, &count);
+    if (status != SEC_E_BUFFER_TOO_SMALL) goto done;
+    if (!(certs = malloc( size )))
+    {
+        status = SEC_E_INSUFFICIENT_MEMORY;
+        goto done;
+    }
+    status = schan_funcs->get_session_peer_certificate(ctx->transport.session, certs, &size, &count);
+    if (status == SEC_E_OK)
     {
         unsigned int i;
-        for (i = 0; i < list.count; i++)
+        for (i = 0; i < count; i++)
         {
-            if (!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, list.certs[i].pbData,
-                                                  list.certs[i].cbData, CERT_STORE_ADD_REPLACE_EXISTING,
+            if (!CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, certs[i].pbData,
+                                                  certs[i].cbData, CERT_STORE_ADD_REPLACE_EXISTING,
                                                   i ? NULL : &cert))
             {
                 if (i) CertFreeCertificateContext(cert);
                 return GetLastError();
             }
         }
-        RtlFreeHeap(GetProcessHeap(), 0, list.certs);
     }
-
+    free(certs);
+done:
     ctx->cert = cert;
     CertCloseStore(store, 0);
     return status;
diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c
index 8a540035bdc..392d10e538b 100644
--- a/dlls/secur32/schannel_gnutls.c
+++ b/dlls/secur32/schannel_gnutls.c
@@ -810,28 +810,36 @@ static ALG_ID CDECL schan_get_key_signature_algorithm(schan_session session)
     }
 }
 
-static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, struct schan_cert_list *list)
+static SECURITY_STATUS CDECL schan_get_session_peer_certificate(schan_session session, CERT_BLOB *certs,
+                                                                ULONG *bufsize, ULONG *retcount)
 {
     gnutls_session_t s = (gnutls_session_t)session;
     const gnutls_datum_t *datum;
     unsigned int i, size;
     BYTE *ptr;
+    unsigned int count;
 
-    if (!(datum = pgnutls_certificate_get_peers(s, &list->count))) return SEC_E_INTERNAL_ERROR;
+    if (!(datum = pgnutls_certificate_get_peers(s, &count))) return SEC_E_INTERNAL_ERROR;
 
-    size = list->count * sizeof(list->certs[0]);
-    for (i = 0; i < list->count; i++) size += datum[i].size;
-    if (!(list->certs = RtlAllocateHeap(GetProcessHeap(), 0, size))) return SEC_E_INSUFFICIENT_MEMORY;
+    size = count * sizeof(certs[0]);
+    for (i = 0; i < count; i++) size += datum[i].size;
 
-    ptr = (BYTE *)&list->certs[list->count];
-    for (i = 0; i < list->count; i++)
+    if (!certs || *bufsize < size)
     {
-        list->certs[i].cbData = datum[i].size;
-        list->certs[i].pbData = ptr;
-        memcpy(list->certs[i].pbData, datum[i].data, datum[i].size);
+        *bufsize = size;
+        return SEC_E_BUFFER_TOO_SMALL;
+    }
+    ptr = (BYTE *)&certs[count];
+    for (i = 0; i < count; i++)
+    {
+        certs[i].cbData = datum[i].size;
+        certs[i].pbData = ptr;
+        memcpy(certs[i].pbData, datum[i].data, datum[i].size);
         ptr += datum[i].size;
     }
 
+    *bufsize = size;
+    *retcount = count;
     return SEC_E_OK;
 }
 
diff --git a/dlls/secur32/secur32_priv.h b/dlls/secur32/secur32_priv.h
index 3552a6aaf38..7cad59a51f7 100644
--- a/dlls/secur32/secur32_priv.h
+++ b/dlls/secur32/secur32_priv.h
@@ -108,12 +108,6 @@ struct schan_transport
     struct schan_buffers out;
 };
 
-struct schan_cert_list
-{
-    unsigned int count;
-    CERT_BLOB   *certs;
-};
-
 struct schan_funcs
 {
     BOOL (CDECL *allocate_certificate_credentials)(schan_credentials *, const CERT_CONTEXT *, const DATA_BLOB *);
@@ -126,7 +120,7 @@ struct schan_funcs
     ALG_ID (CDECL *get_key_signature_algorithm)(schan_session);
     unsigned int (CDECL *get_max_message_size)(schan_session);
     unsigned int (CDECL *get_session_cipher_block_size)(schan_session);
-    SECURITY_STATUS (CDECL *get_session_peer_certificate)(schan_session, struct schan_cert_list *);
+    SECURITY_STATUS (CDECL *get_session_peer_certificate)(schan_session, CERT_BLOB *, ULONG *, ULONG *);
     SECURITY_STATUS (CDECL *get_unique_channel_binding)(schan_session, SecPkgContext_Bindings *);
     SECURITY_STATUS (CDECL *handshake)(schan_session, SecBufferDesc *, SIZE_T, SecBufferDesc *, ULONG );
     SECURITY_STATUS (CDECL *recv)(schan_session, SecBufferDesc *, SIZE_T, void *, SIZE_T *);




More information about the wine-cvs mailing list