secur32/tests: Add tests for the Kerberos provider.

Hans Leidekker hans at codeweavers.com
Mon Oct 16 03:07:30 CDT 2017


For reference, these are some of the tests I used to develop these patches. We probably
don't want to include them because a successful run requires a specific machine configuration
that most of us don't have.

Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/secur32/tests/Makefile.in |   1 +
 dlls/secur32/tests/kerberos.c  | 368 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 369 insertions(+)
 create mode 100644 dlls/secur32/tests/kerberos.c

diff --git a/dlls/secur32/tests/Makefile.in b/dlls/secur32/tests/Makefile.in
index 089d1c3117..7994d1d025 100644
--- a/dlls/secur32/tests/Makefile.in
+++ b/dlls/secur32/tests/Makefile.in
@@ -2,6 +2,7 @@ TESTDLL   = secur32.dll
 IMPORTS   = secur32 crypt32 advapi32 ws2_32
 
 C_SRCS = \
+	kerberos.c \
 	main.c \
 	negotiate.c \
 	ntlm.c \
diff --git a/dlls/secur32/tests/kerberos.c b/dlls/secur32/tests/kerberos.c
new file mode 100644
index 0000000000..e846f1b510
--- /dev/null
+++ b/dlls/secur32/tests/kerberos.c
@@ -0,0 +1,368 @@
+/*
+ * Tests for the Kerberos security provider
+ *
+ * Copyright 2005, 2006 Kai Blin
+ * Copyright 2017 Hans Leidekker for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <windef.h>
+#include <winbase.h>
+#define SECURITY_WIN32
+#include <sspi.h>
+#include <rpc.h>
+#include <rpcdce.h>
+#include <secext.h>
+
+#include "wine/test.h"
+
+/* This should be changed to match your environment. */
+#define TEST_SERVICE_PRINCIPAL (SEC_CHAR *)"HTTP/user.test.local at TEST.LOCAL"
+
+/* A succesful test run requires a properly configured machine:
+ *
+ * 1. Kerberos authentication must be configured for realm TEST.LOCAL (see /etc/krb5.conf).
+ * 2. Account 'user' must exist and have principal HTTP/user.test.local at TEST.LOCAL mapped to it.
+ * 3. A keytab for the service must be generated and made accessible, e.g. through $KRB5_KTNAME.
+ * 4. The Unix user must obtain a ticket for the service, e.g. by running this command:
+ *
+ *    kinit HTTP/user.test.local at TEST.LOCAL
+ */
+
+#define KERBEROS_BASE_CAPS \
+    ( SECPKG_FLAG_INTEGRITY \
+    | SECPKG_FLAG_PRIVACY \
+    | SECPKG_FLAG_TOKEN_ONLY \
+    | SECPKG_FLAG_DATAGRAM \
+    | SECPKG_FLAG_CONNECTION \
+    | SECPKG_FLAG_MULTI_REQUIRED \
+    | SECPKG_FLAG_EXTENDED_ERROR \
+    | SECPKG_FLAG_IMPERSONATION \
+    | SECPKG_FLAG_ACCEPT_WIN32_NAME \
+    | SECPKG_FLAG_NEGOTIABLE \
+    | SECPKG_FLAG_GSS_COMPATIBLE \
+    | SECPKG_FLAG_LOGON \
+    | SECPKG_FLAG_MUTUAL_AUTH \
+    | SECPKG_FLAG_DELEGATION \
+    | SECPKG_FLAG_READONLY_WITH_CHECKSUM \
+    | SECPKG_FLAG_RESTRICTED_TOKENS)
+
+struct sspi_data
+{
+    CredHandle cred;
+    CtxtHandle ctxt;
+    SecBufferDesc in_buf;
+    SecBufferDesc out_buf;
+    ULONG max_token;
+};
+
+static void cleanup_buffers( struct sspi_data *data )
+{
+    unsigned int i;
+
+    for (i = 0; i < data->in_buf.cBuffers; i++)
+        HeapFree( GetProcessHeap(), 0, data->in_buf.pBuffers[i].pvBuffer );
+
+    for (i = 0; i < data->out_buf.cBuffers; i++)
+        HeapFree( GetProcessHeap(), 0, data->out_buf.pBuffers[i].pvBuffer );
+
+    HeapFree( GetProcessHeap(), 0, data->in_buf.pBuffers );
+    HeapFree( GetProcessHeap(), 0, data->out_buf.pBuffers );
+}
+
+static void setup_buffers( struct sspi_data *data, SecPkgInfoA *info )
+{
+    SecBuffer *buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
+
+    data->max_token = info->cbMaxToken;
+
+    data->in_buf.ulVersion = SECBUFFER_VERSION;
+    data->in_buf.cBuffers  = 1;
+    data->in_buf.pBuffers  = buffer;
+
+    buffer->cbBuffer   = info->cbMaxToken;
+    buffer->BufferType = SECBUFFER_TOKEN;
+    buffer->pvBuffer   = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
+
+    buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(SecBuffer) );
+
+    data->out_buf.ulVersion = SECBUFFER_VERSION;
+    data->out_buf.cBuffers  = 1;
+    data->out_buf.pBuffers  = buffer;
+
+    buffer->cbBuffer   = info->cbMaxToken;
+    buffer->BufferType = SECBUFFER_TOKEN;
+    buffer->pvBuffer   = HeapAlloc( GetProcessHeap(), 0, info->cbMaxToken );
+}
+
+static SECURITY_STATUS setup_client( struct sspi_data *data )
+{
+    SECURITY_STATUS ret;
+    SecPkgInfoA *info;
+    TimeStamp ttl;
+
+    trace( "setting up client\n" );
+
+    ret = QuerySecurityPackageInfoA( (SEC_CHAR *)"Kerberos", &info );
+    ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08x\n", ret );
+
+    setup_buffers( data, info );
+    FreeContextBuffer( info );
+
+    ret = AcquireCredentialsHandleA( NULL, (SEC_CHAR *)"Kerberos", SECPKG_CRED_OUTBOUND, NULL,
+                                     NULL, NULL, NULL, &data->cred, &ttl );
+    ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08x\n", ret );
+    return ret;
+}
+
+static SECURITY_STATUS setup_server( struct sspi_data *data )
+{
+    SECURITY_STATUS ret;
+    SecPkgInfoA *info;
+    TimeStamp ttl;
+
+    trace( "setting up server\n" );
+
+    ret = QuerySecurityPackageInfoA( (SEC_CHAR *)"Kerberos", &info );
+    ok( ret == SEC_E_OK, "QuerySecurityPackageInfo returned %08x\n", ret );
+
+    setup_buffers( data, info );
+    FreeContextBuffer( info );
+
+    ret = AcquireCredentialsHandleA( NULL, (SEC_CHAR *)"Kerberos", SECPKG_CRED_INBOUND, NULL,
+                                     NULL, NULL, NULL, &data->cred, &ttl );
+    ok( ret == SEC_E_OK, "AcquireCredentialsHandleA returned %08x\n", ret );
+    return ret;
+}
+
+static SECURITY_STATUS run_client( struct sspi_data *data, BOOL first )
+{
+    SECURITY_STATUS ret;
+    TimeStamp ttl;
+    char *buf;
+    ULONG attr = 0, flags =  ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
+                             ISC_REQ_INTEGRITY | ISC_REQ_CONFIDENTIALITY;
+
+    trace( "running client for the %s time\n", first ? "first" : "second" );
+
+    data->out_buf.pBuffers[0].cbBuffer = data->max_token;
+    data->out_buf.pBuffers[0].BufferType = SECBUFFER_TOKEN;
+    buf = data->out_buf.pBuffers[0].pvBuffer;
+    memset( buf, 0x55, data->max_token );
+
+    ret = InitializeSecurityContextA( first ? &data->cred : NULL, first ? NULL : &data->ctxt,
+                                      TEST_SERVICE_PRINCIPAL, flags, 0,
+                                      SECURITY_NETWORK_DREP, first ? NULL : &data->in_buf,
+                                      0, &data->ctxt, &data->out_buf, &attr, &ttl );
+    if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
+    {
+        CompleteAuthToken( &data->ctxt, &data->out_buf );
+        if (ret == SEC_I_COMPLETE_AND_CONTINUE)
+            ret = SEC_I_CONTINUE_NEEDED;
+        else if (ret == SEC_I_COMPLETE_NEEDED)
+            ret = SEC_E_OK;
+    }
+    ok( data->out_buf.pBuffers[0].BufferType == SECBUFFER_TOKEN,
+        "buffer type changed from SECBUFFER_TOKEN to %u\n", data->out_buf.pBuffers[0].BufferType );
+    ok( data->out_buf.pBuffers[0].cbBuffer < data->max_token,
+        "InitializeSecurityContext didn't change buffer size\n" );
+    ok( buf[0] != 0x55, "buffer not modified\n" );
+    return ret;
+}
+
+static SECURITY_STATUS run_server( struct sspi_data *data, BOOL first )
+{
+    SECURITY_STATUS ret;
+    TimeStamp ttl;
+    ULONG attr = 0;
+
+    trace( "running server for the %s time\n", first ? "first" : "second" );
+
+    ret = AcceptSecurityContext( &data->cred, first ? NULL : &data->ctxt, &data->in_buf, 0,
+                                 SECURITY_NETWORK_DREP, &data->ctxt, &data->out_buf, &attr, &ttl );
+    if (ret == SEC_I_COMPLETE_AND_CONTINUE || ret == SEC_I_COMPLETE_NEEDED)
+    {
+        CompleteAuthToken( &data->ctxt, &data->out_buf );
+        if (ret == SEC_I_COMPLETE_AND_CONTINUE)
+            ret = SEC_I_CONTINUE_NEEDED;
+        else if (ret == SEC_I_COMPLETE_NEEDED)
+            ret = SEC_E_OK;
+    }
+    return ret;
+}
+
+static void communicate( struct sspi_data *from, struct sspi_data *to )
+{
+    trace( "running communicate\n" );
+    memset( to->in_buf.pBuffers[0].pvBuffer, 0, to->max_token );
+    memcpy( to->in_buf.pBuffers[0].pvBuffer, from->out_buf.pBuffers[0].pvBuffer,
+            from->out_buf.pBuffers[0].cbBuffer );
+    to->in_buf.pBuffers[0].cbBuffer = from->out_buf.pBuffers[0].cbBuffer;
+    memset( from->out_buf.pBuffers[0].pvBuffer, 0, from->max_token );
+}
+
+static void test_authentication(void)
+{
+    SECURITY_STATUS status_c = SEC_I_CONTINUE_NEEDED,
+                    status_s = SEC_I_CONTINUE_NEEDED, status;
+    struct sspi_data client, server;
+    SecPkgContext_Sizes sizes;
+    char data[128];
+    SecBuffer buf[2];
+    SecBufferDesc desc;
+    BOOL first = TRUE;
+
+    status = FreeCredentialsHandle( NULL );
+    ok( status == SEC_E_INVALID_HANDLE, "FreeCredentialsHandle returned %08x\n", status );
+
+    memset( &client, 0, sizeof(client) );
+    memset( &server, 0, sizeof(server) );
+
+    if ((status = setup_client( &client )))
+    {
+        skip( "setup_client returned %08x, skipping test\n", status );
+        return;
+    }
+    if ((status = setup_server( &server )))
+    {
+        skip( "setup_server returned %08x, skipping test\n", status );
+        FreeCredentialsHandle( &client.cred );
+        return;
+    }
+
+    while (status_c == SEC_I_CONTINUE_NEEDED && status_s == SEC_I_CONTINUE_NEEDED)
+    {
+        status_c = run_client( &client, first );
+        ok( status_c == SEC_E_OK || status_c == SEC_I_CONTINUE_NEEDED,
+            "client returned %08x, more tests will fail\n", status_c );
+
+        communicate( &client, &server );
+
+        status_s = run_server( &server, first );
+        ok( status_s == SEC_E_OK || status_s == SEC_I_CONTINUE_NEEDED,
+            "server returned %08x, more tests will fail\n", status_s );
+
+        communicate( &server, &client );
+        trace( "looping\n");
+        first = FALSE;
+    }
+    if (status_c != SEC_E_OK)
+    {
+        skip( "authentication failed, skipping remaining tests\n" );
+        goto done;
+    }
+
+    sizes.cbMaxToken        = 0xdeadbeef;
+    sizes.cbMaxSignature    = 0xdeadbeef;
+    sizes.cbSecurityTrailer = 0xdeadbeef;
+    sizes.cbBlockSize       = 0xdeadbeef;
+    status_c = QueryContextAttributesA( &client.ctxt, SECPKG_ATTR_SIZES, &sizes );
+    ok( status_c == SEC_E_OK, "pQueryContextAttributesA returned %08x\n", status_c );
+    ok( sizes.cbMaxToken == 12000, "expected 12000, got %u\n", sizes.cbMaxToken );
+    ok( sizes.cbMaxSignature == 37, "expected 37, got %u\n", sizes.cbMaxSignature );
+    ok( sizes.cbSecurityTrailer == 49, "expected 49, got %u\n", sizes.cbSecurityTrailer );
+    ok( sizes.cbBlockSize == 1, "expected 1, got %u\n", sizes.cbBlockSize );
+
+    memcpy( data, "test message", sizeof("test message") );
+    buf[0].BufferType = SECBUFFER_DATA;
+    buf[0].cbBuffer   = sizeof("test message");
+    buf[0].pvBuffer   = data;
+
+    buf[1].BufferType = SECBUFFER_TOKEN;
+    buf[1].cbBuffer   = sizes.cbMaxToken;
+    buf[1].pvBuffer   = HeapAlloc( GetProcessHeap(), 0, sizes.cbMaxToken );
+    memset( buf[1].pvBuffer, 0x55, sizes.cbMaxToken );
+
+    desc.ulVersion = SECBUFFER_VERSION;
+    desc.cBuffers  = 2;
+    desc.pBuffers  = buf;
+
+    status = EncryptMessage( &client.ctxt, 0, &desc, 0 );
+    ok( status == SEC_E_OK, "got %08x\n", status );
+    ok( buf[0].BufferType == SECBUFFER_DATA, "got %u\n", buf[0].BufferType );
+    ok( buf[0].cbBuffer == sizeof("test message"), "got %u\n", buf[0].cbBuffer );
+    ok( memcmp( buf[0].pvBuffer, "test message", sizeof("test message") ), "wrong data\n" );
+
+    ok( buf[1].BufferType == SECBUFFER_TOKEN, "got %u\n", buf[1].BufferType );
+    ok( buf[1].cbBuffer > 0 && buf[1].cbBuffer < sizes.cbMaxToken, "got %u\n", buf[1].cbBuffer );
+    ok( *(char *)buf[1].pvBuffer != 0x55, "buffer not modified\n" );
+
+    status = DecryptMessage( &server.ctxt, &desc, 0, NULL );
+    ok( status == SEC_E_OK, "got %08x\n", status );
+    ok( buf[0].BufferType == SECBUFFER_DATA, "got %u\n", buf[0].BufferType );
+    ok( buf[0].cbBuffer == sizeof("test message"), "got %u\n", buf[0].cbBuffer );
+    ok( !memcmp( buf[0].pvBuffer, "test message", sizeof("test message") ), "wrong data\n" );
+    HeapFree( GetProcessHeap(), 0, buf[1].pvBuffer );
+
+    memcpy( data, "test message", sizeof("test message") );
+    buf[0].BufferType = SECBUFFER_DATA;
+    buf[0].cbBuffer   = sizeof("test message");
+    buf[0].pvBuffer   = data;
+
+    buf[1].BufferType = SECBUFFER_TOKEN;
+    buf[1].cbBuffer   = sizes.cbMaxSignature;
+    buf[1].pvBuffer   = HeapAlloc( GetProcessHeap(), 0, sizes.cbMaxSignature );
+    memset( buf[1].pvBuffer, 0x55, sizes.cbMaxSignature );
+
+    status = MakeSignature( &client.ctxt, 0, &desc, 0 );
+    ok( status == SEC_E_OK, "got %08x\n", status );
+    ok( buf[0].BufferType == SECBUFFER_DATA, "got %u\n", buf[0].BufferType );
+    ok( buf[0].cbBuffer == sizeof("test message"), "got %u\n", buf[0].cbBuffer );
+    ok( !memcmp( buf[0].pvBuffer, "test message", sizeof("test message") ), "wrong data\n" );
+
+    ok( buf[1].BufferType == SECBUFFER_TOKEN, "got %u\n", buf[1].BufferType );
+    todo_wine ok( buf[1].cbBuffer == sizes.cbMaxSignature, "got %u\n", buf[1].cbBuffer );
+    ok( *(char *)buf[1].pvBuffer != 0x55, "buffer not modified\n" );
+
+    status = VerifySignature( &server.ctxt, &desc, 0, NULL );
+    ok( status == SEC_E_OK, "got %08x\n", status );
+
+    HeapFree( GetProcessHeap(), 0, buf[1].pvBuffer );
+
+done:
+    cleanup_buffers( &client );
+    cleanup_buffers( &server );
+
+    status_c = DeleteSecurityContext( &client.ctxt );
+    ok( status_c == SEC_E_OK, "DeleteSecurityContext returned %08x\n", status_c );
+    status_s = DeleteSecurityContext( &server.ctxt );
+    ok( status_s == SEC_E_OK, "DeleteSecurityContext returned %08x\n", status_s );
+
+    status_c = FreeCredentialsHandle( &client.cred );
+    ok( status_c == SEC_E_OK, "FreeCredentialsHandle returned %08x\n", status_c );
+    status_s = FreeCredentialsHandle( &server.cred );
+    ok( status_s == SEC_E_OK, "FreeCredentialsHandle returned %08x\n", status_s );
+}
+
+START_TEST(kerberos)
+{
+    SecPkgInfoA *info;
+
+    if (QuerySecurityPackageInfoA( (SEC_CHAR *)"Kerberos", &info ))
+    {
+        ok( 0, "Kerberos package not installed, skipping test\n" );
+        return;
+    }
+    ok( info->fCapabilities == KERBEROS_BASE_CAPS, "got %08x\n", info->fCapabilities );
+    ok( info->wVersion == 1, "got %u\n", info->wVersion );
+    ok( info->wRPCID == RPC_C_AUTHN_GSS_KERBEROS, "got %u\n", info->wRPCID );
+    ok( !lstrcmpA( info->Name, "Kerberos" ), "got %s\n", info->Name );
+    FreeContextBuffer( info );
+
+    test_authentication();
+}
-- 
2.11.0




More information about the wine-patches mailing list