3

我想构建新版本的 Open Pegasus Client (2.14.1)。不幸的是,我面临一些构建问题。有人知道这些问题的一些解决方法吗?

我的环境是:

  • 操作系统:Windows 8.1 企业版
  • 制作版本:GNU Make 3.81
  • Pegasus 源版本:2.14.1
  • OpenSSL 版本:1.0.2a

我的场景很简单:

  1. 我已经下载了 Open Pegasus 2.14.1 的源代码
  2. 我已经下载了 OpenSSL 二进制文件(实际版本 v1.0.2a)。
  3. 提取 Pegasus 源代码后,我使用以下设置设置环境:

    call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat"
    set PEGASUS_ROOT=D:/Dev/pegasus-2.14.1/pegasus
    set PEGASUS_HOME=%PEGASUS_ROOT%
    set PEGASUS_PLATFORM=WIN32_IX86_MSVC
    set path=%path%;%PEGASUS_HOME%\bin
    set OPENSSL_HOME=D:/Dev/OpenSSL-Win32
    set PEGASUS_HAS_SSL=true
    
  4. 下一步是构建 mu.exe 工具。所以,我已经执行了“make buildmu”=>成功构建并复制到“/bin”文件夹。我想这样构建 Pegasus:“make build”=> 一段时间后我得到了这个错误:

    Message.cpp(433):错误 C2065:'magic':未声明的标识符

  5. 我试图解决这个问题。我发现魔术常数是在 \pegasus-2.14.1\pegasus\src\Pegasus\Common\Linkable.h 文件中定义的,所以我有两个选择:a)将构建配置切换到 DEBUG(设置 PEGASUS_DEBUG=true) b)删除 DEBUG Linkable.h 文件中第 62 行的条件 然后,我尝试再次构建 Pegasus,不幸的是我收到了这个错误:

    错误 LNK2005:_OPENSSL_Applink 已在 SSLContext.obj 中定义

在这一点上,我不知道如何解决这个问题。我只是试图删除这些行:

# ifdef PEGASUS_OS_TYPE_WINDOWS
 # include<openssl/applink.c>
# endif

来自 SSLContextRep.h 文件。在这个修改之后,我能够获得 Pegasus 客户端二进制文件。但是这些二进制文件在没有 SSL 的情况下工作,当我想使用 SSL 通信时,我总是收到错误:“Pegasus Exception: 'Cannot connect to 10.199.1.139:5989. Connection failed.'.”,所以我认为这是因为我的代码修改在 SSLContextRep.h 中。

Pegasus Tracer 的输出:

SSL:未连接 1 错误:140740BF:SSL 例程:SSL23_CLIENT_HELLO:没有可用的协议 SSL:已删除 SSL 套接字

有人知道有什么问题吗?是否有人拥有一些(更好的)Windows 环境配置步骤来构建 OpenPegasus?

非常感谢您提供的任何帮助。


编辑:

我需要能够在没有证书的情况下工作。因为我正在使用 SSL 与各种存储阵列进行通信,但我没有他们的证书。因此我使用 SSLContext 的这个构造函数:

SSLContext sslContext(String::EMPTY, NULL, String::EMPTY);

这种方法在 OpenPegasus 2.13 版本中对我很有效。

4

2 回答 2

1
Outputs from Pegasus Tracer:

    SSL: Not connected 1 error:140740BF:SSL routines:SSL23_CLIENT_HELLO:no protocols available SSL: Deleted SSL socket

这是消息的来源:

$ grep -nR "Deleted SSL socket" *
src/Pegasus/Common/TLS.cpp:172:    PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: Deleted SSL socket");

第 172 行的代码:

SSLSocket::~SSLSocket()
{
    PEG_METHOD_ENTER(TRC_SSL, "SSLSocket::~SSLSocket()");

    close();
    delete static_cast<SharedPtr<X509_STORE, FreeX509STOREPtr>*>(_crlStore);
    SSL_free(static_cast<SSL*>(_SSLConnection));

    PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: Deleted SSL socket");

    PEG_METHOD_EXIT();
}

如果您查看.../src/Pegasus/Common/SSLContext.cpp,您将看到:

SSL_CTX* SSLContextRep::_makeSSLContext()
{
    PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");

    //
    // create SSL Context Area
    //
    SSL_CTX *sslContext = NULL;
    if (!(sslContext = SSL_CTX_new(SSLv23_method())))
    {
        PEG_METHOD_EXIT();
        MessageLoaderParms parms(
            "Common.SSLContext.COULD_NOT_GET",
            "Could not get SSL CTX");
        throw SSLException(parms);
    }

    int options = SSL_OP_ALL;

    SSL_CTX_set_options(sslContext, options);
    if ( _sslCompatibility == false )
    {

#ifdef TLS1_2_VERSION
        // Enable only TLSv1.2 and disable all other protocol (SSL v2, SSL v3,
        // TLS v1.0, TLSv1.1)

        options = SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_SSLv3;
#else
        PEG_METHOD_EXIT();
        MessageLoaderParms parms(
            " Common.SSLContext.TLS_1_2_PROTO_NOT_SUPPORTED",
            "TLSv1.2 protocol support is not detected on this system. "
            " To run in less secured mode, set sslBackwardCompatibility=true"
            " in planned config file and start cimserver.");
        throw SSLException(parms);
#endif
    }

    // sslv2 is off permanently even if sslCompatibility is true
    options |= SSL_OP_NO_SSLv2;
    SSL_CTX_set_options(sslContext, options);

#ifdef PEGASUS_SSL_WEAKENCRYPTION
    if (!(SSL_CTX_set_cipher_list(sslContext, SSL_TXT_EXP40)))
    {
        SSL_CTX_free(sslContext);
        sslContext = NULL;

        MessageLoaderParms parms(
            "Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
            "Could not set the cipher list");
        throw SSLException(parms);
    }
#endif

    if (_cipherSuite.size() != 0)
    {
        if (!(SSL_CTX_set_cipher_list(sslContext, _cipherSuite.getCString())))
        {
            SSL_CTX_free(sslContext);
            sslContext = NULL;

            PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3,
                "---> SSL: Cipher Suite could not be specified");
            MessageLoaderParms parms(
                "Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
                "Could not set the cipher list");
            throw SSLException(parms);
        }
        else
        {
           PEG_TRACE((TRC_SSL, Tracer::LEVEL3,
                "---> SSL: Cipher suite set to %s",
                (const char *)_cipherSuite.getCString()));
        }
    }
    ...
}

我会出于两个原因放弃该功能,并添加类似以下内容。

首先,它是编写为既是客户端又是服务器的非晶例程之一。我从使用 OpenSSL 的经验中发现,你有单独的函数SSL_CTX* GetClientContext()SSL_CTX* GetServerContext().

其次,从安全工程的角度来看,你不允许人们进入一个糟糕的状态,比如PEGASUS_SSL_WEAKENCRYPTION一个空的密码列表。你把枪拿走,这样他们就不会在脚上开枪了。

SSL_CTX* SSLContextRep::_makeSSLContext()
{
    PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()");

    SSL_CTX *sslContext = NULL;
    if (!(sslContext = SSL_CTX_new(SSLv23_method())))
    {
        PEG_METHOD_EXIT();
        MessageLoaderParms parms(
            "Common.SSLContext.COULD_NOT_GET",
            "Could not get SSL CTX");
        throw SSLException(parms);
    }       

    // TLS 1.0 and above. No compression because it leaks information.
    static const long options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
    SSL_CTX_set_options(sslContext, options);

    const char* const PREFERRED_CIPHERS = "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4";
    int res = SSL_set_cipher_list(sslContext, PREFERRED_CIPHERS);
    if(res != 1)
    {
        PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3,
            "---> SSL: Cipher Suite could not be specified");
        MessageLoaderParms parms(
            "Common.SSLContext.COULD_NOT_SET_CIPHER_LIST",
            "Could not set the cipher list");
        throw SSLException(parms);
    }

    // Keep this stuff
    SSL_CTX_set_quiet_shutdown(sslContext, 1);
    SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY);
    SSL_CTX_set_mode(sslContext, SSL_MODE_ENABLE_PARTIAL_WRITE);
    SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF);        
    SSL_CTX_set_mode(sslContext, SSL_MODE_RELEASE_BUFFERS);

    // Back to gutting. We don't allow VERIFY_PEER_NONE.
    {
        PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
            "---> SSL: certificate verification callback specified");
        SSL_CTX_set_verify(sslContext,
            SSL_VERIFY_PEER, prepareForCallback);
    }

    // Some more gutting. Certificates have to be verified.
    if(_trustStore.size() == 0)
    {
        PEG_TRACE((TRC_SSL, Tracer::LEVEL1,
                "---> SSL: Could not load certificates from the "
                "trust store: %s",
                (const char*)_trustStore.getCString()));
        MessageLoaderParms parms(
                "Common.SSLContext.COULD_NOT_LOAD_CERTIFICATES",
                "Could not load certificates in to trust store.");
        SSL_CTX_free(sslContext);
        sslContext = NULL;

        PEG_METHOD_EXIT();
        throw SSLException(parms);
    }

    if ( !SSL_CTX_load_verify_locations(
        sslContext, _trustStore.getCString(), NULL) )
        {
            PEG_TRACE((TRC_SSL, Tracer::LEVEL1,
                "---> SSL: Could not load certificates from the "
                "trust store: %s",
                (const char*)_trustStore.getCString()));
            MessageLoaderParms parms(
                "Common.SSLContext.COULD_NOT_LOAD_CERTIFICATES",
                "Could not load certificates in to trust store.");
            SSL_CTX_free(sslContext);
            sslContext = NULL;

            PEG_METHOD_EXIT();
            throw SSLException(parms);
        }

     // I'm not sure what to do with CRLs. They are usually a DoS waiting to happen....
     if (_crlPath.size() != 0)
     {
        // need to save this -- can we make it static since there's only
        // one CRL for cimserver?
        X509_LOOKUP* pLookup;

        _crlStore.reset(X509_STORE_new());
        if (_crlStore.get() == NULL)
        {
            SSL_CTX_free(sslContext);
            sslContext = NULL;
            PEG_METHOD_EXIT();
            throw PEGASUS_STD(bad_alloc)();
        }

        // the validity of the crlstore was checked in ConfigManager
        // during server startup
        if (FileSystem::isDirectory(_crlPath))
        {
            PEG_TRACE((TRC_SSL, Tracer::LEVEL4,
                "---> SSL: CRL store is a directory in %s",
                (const char*)_crlPath.getCString()));

            if ((pLookup = X509_STORE_add_lookup(
                     _crlStore.get(), X509_LOOKUP_hash_dir())) == NULL)
            {
                MessageLoaderParms parms(
                    "Common.SSLContext.COULD_NOT_LOAD_CRLS",
                    "Could not load certificate revocation list.");
                _crlStore.reset();
                SSL_CTX_free(sslContext);
                sslContext = NULL;
                PEG_METHOD_EXIT();
                throw SSLException(parms);
            }

            X509_LOOKUP_add_dir(
                pLookup, (const char*)_crlPath.getCString(), X509_FILETYPE_PEM);

            PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL3,
                "---> SSL: Successfully configured CRL directory");
        }
        else
        {
            PEG_TRACE((TRC_SSL, Tracer::LEVEL4,
                "---> SSL: CRL store is the file %s",
                (const char*)_crlPath.getCString()));

            if ((pLookup = X509_STORE_add_lookup(
                   _crlStore.get(), X509_LOOKUP_file())) == NULL)
            {
                MessageLoaderParms parms(
                    "Common.SSLContext.COULD_NOT_LOAD_CRLS",
                    "Could not load certificate revocation list.");
                _crlStore.reset();
                SSL_CTX_free(sslContext);
                sslContext = NULL;
                PEG_METHOD_EXIT();
                throw SSLException(parms);
            }

            X509_LOOKUP_load_file(
                pLookup, (const char*)_crlPath.getCString(), X509_FILETYPE_PEM);

            PEG_TRACE_CSTRING(TRC_SSL, Tracer::LEVEL4,
                "---> SSL: Successfully configured CRL file");
        }
    }

    Boolean keyLoaded = false;

    // Gut server specific certificate and key routines since this is a client.

    PEG_METHOD_EXIT();
    return sslContext;
}

TLS 1.2 和 AEAD 密码套件是一个很好的选择。但是,对于大多数意图和目的而言,TLS 1.0 及更高版本都可以。


我认为这可能是0x140740BF 在客户端的原因。它来自第SSLContext.cpp824 行:

SSL_CTX_set_verify(sslContext,
    SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback);

看起来服务器需要证书。

...但通常您会收到不同的 TLS 警报。


并且消息来源没有调用SSL_set_tlsext_host_name,因此 SNI 似乎已损坏。您可能应该为此提交一份错误报告...

$ grep -nR SSL_set_tlsext_host_name *
$

您必须弄清楚客户端在哪里建立连接,并将其设置为SSL*选项:

SSL_set_tlsext_host_name(ssl, hostname);

某个地方SSLSocket::SSLSocket可能是一个不错的选择,因为它的构造函数接受一个字符串,并且sslConnection在 ctor 中可用。

SSLSocket::SSLSocket(
    SocketHandle socket,
    SSLContext * sslcontext,
    ReadWriteSem * sslContextObjectLock,
    const String& ipAddress)

但我很确定你需要一个 DNS 名称而不是 IP 地址,因为在同一个 IP 上多路复用不同服务器是首先需要 SNI 的原因。

但我可能是错的。const String& ipAddress实际上可能是 DNS 名称。

于 2015-06-01T14:21:10.613 回答
1

我收到了 Open Pegasus 开发团队的回复。他们为“魔术”常量的问题创建了错误。他们还建议在我的情况下使用 sslBackwardCompatibility = true 配置进行构建。

这个设置对我有部分帮助。对于某些存储阵列,SSL 通信开始工作。但对于某些人来说,它仍然报告“无法连接”异常。

我发现的唯一解决方法是将 _makeSSLContext() 方法的代码替换为 OpenPegasus 2.13 版本的代码。进行此修改后,我可以将 SSL 通信与我的所有存储阵列 + 新 Pegasus 版本的所有功能一起使用。

于 2015-06-06T18:21:39.767 回答