libwinpr-sspi: started OpenSSL-based Schannel implementation
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Mon, 24 Dec 2012 01:20:41 +0000 (20:20 -0500)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Mon, 24 Dec 2012 01:20:41 +0000 (20:20 -0500)
winpr/libwinpr/sspi/CMakeLists.txt
winpr/libwinpr/sspi/Schannel/schannel.c
winpr/libwinpr/sspi/Schannel/schannel.h
winpr/libwinpr/sspi/Schannel/schannel_openssl.c [new file with mode: 0644]
winpr/libwinpr/sspi/Schannel/schannel_openssl.h [new file with mode: 0644]
winpr/libwinpr/sspi/sspi.h

index f969e0e..d6c6568 100644 (file)
@@ -33,6 +33,8 @@ set(${MODULE_PREFIX}_NEGOTIATE_SRCS
        Negotiate/negotiate.h)
 
 set(${MODULE_PREFIX}_SCHANNEL_SRCS
+       Schannel/schannel_openssl.c
+       Schannel/schannel_openssl.h
        Schannel/schannel.c
        Schannel/schannel.h)
 
index 720fbd3..3757e26 100644 (file)
@@ -39,6 +39,8 @@ SCHANNEL_CONTEXT* schannel_ContextNew()
        if (context != NULL)
        {
                ZeroMemory(context, sizeof(SCHANNEL_CONTEXT));
+
+               context->openssl = schannel_openssl_new();
        }
 
        return context;
@@ -49,6 +51,8 @@ void schannel_ContextFree(SCHANNEL_CONTEXT* context)
        if (!context)
                return;
 
+       schannel_openssl_free(context->openssl);
+
        free(context);
 }
 
@@ -221,6 +225,8 @@ SECURITY_STATUS SEC_ENTRY schannel_InitializeSecurityContextW(PCredHandle phCred
 
                sspi_SecureHandleSetLowerPointer(phNewContext, context);
                sspi_SecureHandleSetUpperPointer(phNewContext, (void*) SCHANNEL_PACKAGE_NAME);
+
+               schannel_openssl_client_init(context->openssl);
        }
 
        return SEC_E_OK;
@@ -401,7 +407,7 @@ const SecPkgInfoA SCHANNEL_SecPkgInfoA =
        0x000107B3, /* fCapabilities */
        1, /* wVersion */
        0x000E, /* wRPCID */
-       0x00006000, /* cbMaxToken */
+       SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
        "Schannel", /* Name */
        "Schannel Security Package" /* Comment */
 };
@@ -420,7 +426,7 @@ const SecPkgInfoW SCHANNEL_SecPkgInfoW =
        0x000107B3, /* fCapabilities */
        1, /* wVersion */
        0x000E, /* wRPCID */
-       0x00006000, /* cbMaxToken */
+       SCHANNEL_CB_MAX_TOKEN, /* cbMaxToken */
        SCHANNEL_SecPkgInfoW_Name, /* Name */
        SCHANNEL_SecPkgInfoW_Comment /* Comment */
 };
index 3256aca..0ec9a83 100644 (file)
@@ -25,6 +25,8 @@
 
 #include "../sspi.h"
 
+#include "schannel_openssl.h"
+
 struct _SCHANNEL_CREDENTIALS
 {
        SCHANNEL_CRED cred;
@@ -36,6 +38,7 @@ struct _SCHANNEL_CONTEXT
 {
        BOOL server;
        SCHANNEL_CRED cred;
+       SCHANNEL_OPENSSL* openssl;
 };
 typedef struct _SCHANNEL_CONTEXT SCHANNEL_CONTEXT;
 
diff --git a/winpr/libwinpr/sspi/Schannel/schannel_openssl.c b/winpr/libwinpr/sspi/Schannel/schannel_openssl.c
new file mode 100644 (file)
index 0000000..b8a3805
--- /dev/null
@@ -0,0 +1,179 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Schannel Security Package (OpenSSL)
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <winpr/crt.h>
+#include <winpr/sspi.h>
+#include <winpr/print.h>
+
+#include "schannel_openssl.h"
+
+char* openssl_get_ssl_error_string(int ssl_error)
+{
+       switch (ssl_error)
+       {
+               case SSL_ERROR_ZERO_RETURN:
+                       return "SSL_ERROR_ZERO_RETURN";
+
+               case SSL_ERROR_WANT_READ:
+                       return "SSL_ERROR_WANT_READ";
+
+               case SSL_ERROR_WANT_WRITE:
+                       return "SSL_ERROR_WANT_WRITE";
+
+               case SSL_ERROR_SYSCALL:
+                       return "SSL_ERROR_SYSCALL";
+
+               case SSL_ERROR_SSL:
+                       return "SSL_ERROR_SSL";
+       }
+
+       return "SSL_ERROR_UNKNOWN";
+}
+
+int schannel_openssl_client_init(SCHANNEL_OPENSSL* context)
+{
+       int status;
+       int ssl_error;
+       BYTE* ReadBuffer;
+       BYTE* WriteBuffer;
+       long options = 0;
+
+       context->ctx = SSL_CTX_new(TLSv1_client_method());
+
+       if (!context->ctx)
+       {
+               printf("SSL_CTX_new failed\n");
+               return -1;
+       }
+
+       /**
+        * SSL_OP_NO_COMPRESSION:
+        *
+        * The Microsoft RDP server does not advertise support
+        * for TLS compression, but alternative servers may support it.
+        * This was observed between early versions of the FreeRDP server
+        * and the FreeRDP client, and caused major performance issues,
+        * which is why we're disabling it.
+        */
+#ifdef SSL_OP_NO_COMPRESSION
+       options |= SSL_OP_NO_COMPRESSION;
+#endif
+
+       /**
+        * SSL_OP_TLS_BLOCK_PADDING_BUG:
+        *
+        * The Microsoft RDP server does *not* support TLS padding.
+        * It absolutely needs to be disabled otherwise it won't work.
+        */
+       options |= SSL_OP_TLS_BLOCK_PADDING_BUG;
+
+       /**
+        * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:
+        *
+        * Just like TLS padding, the Microsoft RDP server does not
+        * support empty fragments. This needs to be disabled.
+        */
+       options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+
+       SSL_CTX_set_options(context->ctx, options);
+
+       context->ssl = SSL_new(context->ctx);
+
+       if (!context->ssl)
+       {
+               printf("SSL_new failed\n");
+               return -1;
+       }
+
+       context->bioRead = BIO_new(BIO_s_mem());
+
+       if (!context->bioRead)
+       {
+               printf("BIO_new failed\n");
+               return -1;
+       }
+
+       status = BIO_set_write_buf_size(context->bioRead, SCHANNEL_CB_MAX_TOKEN);
+
+       context->bioWrite = BIO_new(BIO_s_mem());
+
+       if (!context->bioWrite)
+       {
+               printf("BIO_new failed\n");
+               return -1;
+       }
+
+       status = BIO_set_write_buf_size(context->bioWrite, SCHANNEL_CB_MAX_TOKEN);
+
+       status = BIO_make_bio_pair(context->bioRead, context->bioWrite);
+
+       SSL_set_bio(context->ssl, context->bioRead, context->bioWrite);
+
+       status = SSL_connect(context->ssl);
+
+       if (status < 0)
+       {
+               ssl_error = SSL_get_error(context->ssl, status);
+               printf("SSL_connect error: %s\n", openssl_get_ssl_error_string(ssl_error));
+       }
+
+       ReadBuffer = (BYTE*) malloc(SCHANNEL_CB_MAX_TOKEN);
+       WriteBuffer = (BYTE*) malloc(SCHANNEL_CB_MAX_TOKEN);
+
+       status = BIO_read(context->bioWrite, ReadBuffer, SCHANNEL_CB_MAX_TOKEN);
+
+       if (status >= 0)
+       {
+               winpr_HexDump(ReadBuffer, status);
+       }
+
+       free(ReadBuffer);
+       free(WriteBuffer);
+
+       return 0;
+}
+
+SCHANNEL_OPENSSL* schannel_openssl_new()
+{
+       SCHANNEL_OPENSSL* context;
+
+       context = (SCHANNEL_OPENSSL*) malloc(sizeof(SCHANNEL_OPENSSL));
+
+       if (context != NULL)
+       {
+               ZeroMemory(context, sizeof(SCHANNEL_OPENSSL));
+
+               SSL_load_error_strings();
+               SSL_library_init();
+       }
+
+       return context;
+}
+
+void schannel_openssl_free(SCHANNEL_OPENSSL* context)
+{
+       if (!context)
+               return;
+
+       free(context);
+}
diff --git a/winpr/libwinpr/sspi/Schannel/schannel_openssl.h b/winpr/libwinpr/sspi/Schannel/schannel_openssl.h
new file mode 100644 (file)
index 0000000..a023b79
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * WinPR: Windows Portable Runtime
+ * Schannel Security Package (OpenSSL)
+ *
+ * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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.
+ */
+
+#ifndef WINPR_SSPI_SCHANNEL_OPENSSL_H
+#define WINPR_SSPI_SCHANNEL_OPENSSL_H
+
+#include <winpr/sspi.h>
+
+#include "../sspi.h"
+
+/* OpenSSL includes windows.h */
+#include <winpr/windows.h>
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/bio.h>
+
+struct _SCHANNEL_OPENSSL
+{
+       SSL* ssl;
+       SSL_CTX* ctx;
+       BIO* bioRead;
+       BIO* bioWrite;
+};
+typedef struct _SCHANNEL_OPENSSL SCHANNEL_OPENSSL;
+
+int schannel_openssl_client_init(SCHANNEL_OPENSSL* context);
+
+SCHANNEL_OPENSSL* schannel_openssl_new();
+void schannel_openssl_free(SCHANNEL_OPENSSL* context);
+
+#endif /* WINPR_SSPI_SCHANNEL_OPENSSL_H */
index b51f723..0144c83 100644 (file)
@@ -22,6 +22,8 @@
 
 #include <winpr/sspi.h>
 
+#define SCHANNEL_CB_MAX_TOKEN  0x00006000
+
 struct _CREDENTIALS
 {
        SEC_WINNT_AUTH_IDENTITY identity;