Пример #1
0
static DWORD netcon_secure_connect_setup(netconn_t *connection, BOOL compat_mode)
{
    SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}};
    SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs};
    SecHandle *cred = &cred_handle;
    BYTE *read_buf;
    SIZE_T read_buf_size = 2048;
    ULONG attrs = 0;
    CtxtHandle ctx;
    SSIZE_T size;
    int bits;
    const CERT_CONTEXT *cert;
    SECURITY_STATUS status;
    DWORD res = ERROR_SUCCESS;

    const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY
        |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION;

    if(!ensure_cred_handle())
        return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;

    if(compat_mode) {
        if(!have_compat_cred_handle)
            return ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
        cred = &compat_cred_handle;
    }

    read_buf = heap_alloc(read_buf_size);
    if(!read_buf)
        return ERROR_OUTOFMEMORY;

    status = InitializeSecurityContextW(cred, NULL, connection->server->name, isc_req_flags, 0, 0, NULL, 0,
            &ctx, &out_desc, &attrs, NULL);

    assert(status != SEC_E_OK);

    while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) {
        if(out_buf.cbBuffer) {
            assert(status == SEC_I_CONTINUE_NEEDED);

            TRACE("sending %lu bytes\n", out_buf.cbBuffer);

            size = sock_send(connection->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
            if(size != out_buf.cbBuffer) {
                ERR("send failed\n");
                status = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
                break;
            }

            FreeContextBuffer(out_buf.pvBuffer);
            out_buf.pvBuffer = NULL;
            out_buf.cbBuffer = 0;
        }

        if(status == SEC_I_CONTINUE_NEEDED) {
            assert(in_bufs[1].cbBuffer < read_buf_size);

            memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer);
            in_bufs[0].cbBuffer = in_bufs[1].cbBuffer;

            in_bufs[1].BufferType = SECBUFFER_EMPTY;
            in_bufs[1].cbBuffer = 0;
            in_bufs[1].pvBuffer = NULL;
        }

        assert(in_bufs[0].BufferType == SECBUFFER_TOKEN);
        assert(in_bufs[1].BufferType == SECBUFFER_EMPTY);

        if(in_bufs[0].cbBuffer + 1024 > read_buf_size) {
            BYTE *new_read_buf;

            new_read_buf = heap_realloc(read_buf, read_buf_size + 1024);
            if(!new_read_buf) {
                status = E_OUTOFMEMORY;
                break;
            }

            in_bufs[0].pvBuffer = read_buf = new_read_buf;
            read_buf_size += 1024;
        }

        size = sock_recv(connection->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0);
        if(size < 1) {
            WARN("recv error\n");
            res = ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
            break;
        }

        TRACE("recv %tu bytes\n", size);

        in_bufs[0].cbBuffer += size;
        in_bufs[0].pvBuffer = read_buf;
        status = InitializeSecurityContextW(cred, &ctx, connection->server->name,  isc_req_flags, 0, 0, &in_desc,
                0, NULL, &out_desc, &attrs, NULL);
        TRACE("InitializeSecurityContext ret %08x\n", status);

        if(status == SEC_E_OK) {
            if(SecIsValidHandle(&connection->ssl_ctx))
                DeleteSecurityContext(&connection->ssl_ctx);
            connection->ssl_ctx = ctx;

            if(in_bufs[1].BufferType == SECBUFFER_EXTRA)
                FIXME("SECBUFFER_EXTRA not supported\n");

            status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &connection->ssl_sizes);
            if(status != SEC_E_OK) {
                WARN("Could not get sizes\n");
                break;
            }

            status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
            if(status == SEC_E_OK) {
                res = netconn_verify_cert(connection, cert, cert->hCertStore);
                CertFreeCertificateContext(cert);
                if(res != ERROR_SUCCESS) {
                    WARN("cert verify failed: %u\n", res);
                    break;
                }
            }else {
                WARN("Could not get cert\n");
                break;
            }

            connection->ssl_buf = heap_alloc(connection->ssl_sizes.cbHeader + connection->ssl_sizes.cbMaximumMessage
                    + connection->ssl_sizes.cbTrailer);
            if(!connection->ssl_buf) {
                res = GetLastError();
                break;
            }
        }
    }

    heap_free(read_buf);

    if(status != SEC_E_OK || res != ERROR_SUCCESS) {
        WARN("Failed to establish SSL connection: %08x (%u)\n", status, res);
        heap_free(connection->ssl_buf);
        connection->ssl_buf = NULL;
        return res ? res : ERROR_INTERNET_SECURITY_CHANNEL_ERROR;
    }

    TRACE("established SSL connection\n");
    connection->secure = TRUE;
    connection->security_flags |= SECURITY_FLAG_SECURE;

    bits = NETCON_GetCipherStrength(connection);
    if (bits >= 128)
        connection->security_flags |= SECURITY_FLAG_STRENGTH_STRONG;
    else if (bits >= 56)
        connection->security_flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
    else
        connection->security_flags |= SECURITY_FLAG_STRENGTH_WEAK;

    if(connection->mask_errors)
        connection->server->security_flags = connection->security_flags;
    return ERROR_SUCCESS;
}
Пример #2
0
int
_mongoc_sspi_auth_sspi_client_step (mongoc_sspi_client_state_t *state,
                                    SEC_CHAR *challenge)
{
   SecBufferDesc inbuf;
   SecBuffer inBufs[1];
   SecBufferDesc outbuf;
   SecBuffer outBufs[1];
   ULONG ignored;
   SECURITY_STATUS status = MONGOC_SSPI_AUTH_GSS_CONTINUE;
   DWORD len;

   if (state->response != NULL) {
      free (state->response);
      state->response = NULL;
   }

   inbuf.ulVersion = SECBUFFER_VERSION;
   inbuf.cBuffers = 1;
   inbuf.pBuffers = inBufs;
   inBufs[0].pvBuffer = NULL;
   inBufs[0].cbBuffer = 0;
   inBufs[0].BufferType = SECBUFFER_TOKEN;
   if (state->haveCtx) {
      inBufs[0].pvBuffer = _mongoc_sspi_base64_decode (challenge, &len);
      if (!inBufs[0].pvBuffer) {
         return MONGOC_SSPI_AUTH_GSS_ERROR;
      }
      inBufs[0].cbBuffer = len;
   }

   outbuf.ulVersion = SECBUFFER_VERSION;
   outbuf.cBuffers = 1;
   outbuf.pBuffers = outBufs;
   outBufs[0].pvBuffer = NULL;
   outBufs[0].cbBuffer = 0;
   outBufs[0].BufferType = SECBUFFER_TOKEN;

   status = InitializeSecurityContextW (/* CredHandle */
                                        &state->cred,
                                        /* CtxtHandle (NULL on first call) */
                                        state->haveCtx ? &state->ctx : NULL,
                                        /* Service Principal Name */
                                        state->spn,
                                        /* Flags */
                                        ISC_REQ_ALLOCATE_MEMORY | state->flags,
                                        /* Always 0 */
                                        0,
                                        /* Target data representation */
                                        SECURITY_NETWORK_DREP,
                                        /* Challenge (NULL on first call) */
                                        state->haveCtx ? &inbuf : NULL,
                                        /* Always 0 */
                                        0,
                                        /* CtxtHandle (Set on first call) */
                                        &state->ctx,
                                        /* Output */
                                        &outbuf,
                                        /* Context attributes */
                                        &ignored,
                                        /* Expiry (We don't use this) */
                                        NULL);
   if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
      _mongoc_sspi_set_gsserror (status, "InitializeSecurityContext");
      status = MONGOC_SSPI_AUTH_GSS_ERROR;
      goto done;
   }
   state->haveCtx = 1;
   if (outBufs[0].cbBuffer) {
      state->response =
         _mongoc_sspi_base64_encode (outBufs[0].pvBuffer, outBufs[0].cbBuffer);
      if (!state->response) {
         status = MONGOC_SSPI_AUTH_GSS_ERROR;
         goto done;
      }
   }
   if (status == SEC_E_OK) {
      /* Get authenticated username. */
      SecPkgContext_NamesW names;
      status = QueryContextAttributesW (&state->ctx, SECPKG_ATTR_NAMES, &names);
      if (status != SEC_E_OK) {
         _mongoc_sspi_set_gsserror (status, "QueryContextAttributesW");
         status = MONGOC_SSPI_AUTH_GSS_ERROR;
         goto done;
      }
      state->username = _mongoc_sspi_wide_to_utf8 (names.sUserName);
      if (state->username == NULL) {
         FreeContextBuffer (names.sUserName);
         status = MONGOC_SSPI_AUTH_GSS_ERROR;
         goto done;
      }
      FreeContextBuffer (names.sUserName);
      status = MONGOC_SSPI_AUTH_GSS_COMPLETE;
   } else {
      status = MONGOC_SSPI_AUTH_GSS_CONTINUE;
   }
done:
   if (inBufs[0].pvBuffer) {
      free (inBufs[0].pvBuffer);
   }
   if (outBufs[0].pvBuffer) {
      FreeContextBuffer (outBufs[0].pvBuffer);
   }
   return status;
}
Пример #3
0
BOOL netconn_secure_connect( netconn_t *conn, WCHAR *hostname )
{
    SecBuffer out_buf = {0, SECBUFFER_TOKEN, NULL}, in_bufs[2] = {{0, SECBUFFER_TOKEN}, {0, SECBUFFER_EMPTY}};
    SecBufferDesc out_desc = {SECBUFFER_VERSION, 1, &out_buf}, in_desc = {SECBUFFER_VERSION, 2, in_bufs};
    BYTE *read_buf;
    SIZE_T read_buf_size = 2048;
    ULONG attrs = 0;
    CtxtHandle ctx;
    SSIZE_T size;
    const CERT_CONTEXT *cert;
    SECURITY_STATUS status;
    DWORD res = ERROR_SUCCESS;

    const DWORD isc_req_flags = ISC_REQ_ALLOCATE_MEMORY|ISC_REQ_USE_SESSION_KEY|ISC_REQ_CONFIDENTIALITY
                                |ISC_REQ_SEQUENCE_DETECT|ISC_REQ_REPLAY_DETECT|ISC_REQ_MANUAL_CRED_VALIDATION;

    if(!ensure_cred_handle())
        return FALSE;

    read_buf = heap_alloc(read_buf_size);
    if(!read_buf)
        return FALSE;

    status = InitializeSecurityContextW(&cred_handle, NULL, hostname, isc_req_flags, 0, 0, NULL, 0,
                                        &ctx, &out_desc, &attrs, NULL);

    assert(status != SEC_E_OK);

    while(status == SEC_I_CONTINUE_NEEDED || status == SEC_E_INCOMPLETE_MESSAGE) {
        if(out_buf.cbBuffer) {
            assert(status == SEC_I_CONTINUE_NEEDED);

            TRACE("sending %u bytes\n", out_buf.cbBuffer);

            size = sock_send(conn->socket, out_buf.pvBuffer, out_buf.cbBuffer, 0);
            if(size != out_buf.cbBuffer) {
                ERR("send failed\n");
                res = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
                break;
            }

            FreeContextBuffer(out_buf.pvBuffer);
            out_buf.pvBuffer = NULL;
            out_buf.cbBuffer = 0;
        }

        if(status == SEC_I_CONTINUE_NEEDED) {
            assert(in_bufs[1].cbBuffer < read_buf_size);

            memmove(read_buf, (BYTE*)in_bufs[0].pvBuffer+in_bufs[0].cbBuffer-in_bufs[1].cbBuffer, in_bufs[1].cbBuffer);
            in_bufs[0].cbBuffer = in_bufs[1].cbBuffer;

            in_bufs[1].BufferType = SECBUFFER_EMPTY;
            in_bufs[1].cbBuffer = 0;
            in_bufs[1].pvBuffer = NULL;
        }

        assert(in_bufs[0].BufferType == SECBUFFER_TOKEN);
        assert(in_bufs[1].BufferType == SECBUFFER_EMPTY);

        if(in_bufs[0].cbBuffer + 1024 > read_buf_size) {
            BYTE *new_read_buf;

            new_read_buf = heap_realloc(read_buf, read_buf_size + 1024);
            if(!new_read_buf) {
                status = E_OUTOFMEMORY;
                break;
            }

            in_bufs[0].pvBuffer = read_buf = new_read_buf;
            read_buf_size += 1024;
        }

        size = sock_recv(conn->socket, read_buf+in_bufs[0].cbBuffer, read_buf_size-in_bufs[0].cbBuffer, 0);
        if(size < 1) {
            WARN("recv error\n");
            status = ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
            break;
        }

        TRACE("recv %lu bytes\n", size);

        in_bufs[0].cbBuffer += size;
        in_bufs[0].pvBuffer = read_buf;
        status = InitializeSecurityContextW(&cred_handle, &ctx, hostname,  isc_req_flags, 0, 0, &in_desc,
                                            0, NULL, &out_desc, &attrs, NULL);
        TRACE("InitializeSecurityContext ret %08x\n", status);

        if(status == SEC_E_OK) {
            if(in_bufs[1].BufferType == SECBUFFER_EXTRA)
                FIXME("SECBUFFER_EXTRA not supported\n");

            status = QueryContextAttributesW(&ctx, SECPKG_ATTR_STREAM_SIZES, &conn->ssl_sizes);
            if(status != SEC_E_OK) {
                WARN("Could not get sizes\n");
                break;
            }

            status = QueryContextAttributesW(&ctx, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
            if(status == SEC_E_OK) {
                res = netconn_verify_cert(cert, hostname, conn->security_flags);
                CertFreeCertificateContext(cert);
                if(res != ERROR_SUCCESS) {
                    WARN("cert verify failed: %u\n", res);
                    break;
                }
            } else {
                WARN("Could not get cert\n");
                break;
            }

            conn->ssl_buf = heap_alloc(conn->ssl_sizes.cbHeader + conn->ssl_sizes.cbMaximumMessage + conn->ssl_sizes.cbTrailer);
            if(!conn->ssl_buf) {
                res = GetLastError();
                break;
            }
        }
    }

    heap_free(read_buf);

    if(status != SEC_E_OK || res != ERROR_SUCCESS) {
        WARN("Failed to initialize security context failed: %08x\n", status);
        heap_free(conn->ssl_buf);
        conn->ssl_buf = NULL;
        DeleteSecurityContext(&ctx);
        set_last_error(res ? res : ERROR_WINHTTP_SECURE_CHANNEL_ERROR);
        return FALSE;
    }


    TRACE("established SSL connection\n");
    conn->secure = TRUE;
    conn->ssl_ctx = ctx;
    return TRUE;
}
Пример #4
0
    int sspiClientMechStep(void *conn_context,
                           sasl_client_params_t *cparams,
                           const char *serverin,
                           unsigned serverinlen,
                           sasl_interact_t **prompt_need,
                           const char **clientout,
                           unsigned *clientoutlen,
                           sasl_out_params_t *oparams) {
        SspiConnContext* pcctx = static_cast<SspiConnContext*>(conn_context);
        *clientout = NULL;
        *clientoutlen = 0;

        if (pcctx->authComplete) {
            return sspiSendClientAuthzId(pcctx, cparams, 
                                         serverin, serverinlen, 
                                         clientout, clientoutlen, 
                                         oparams);
        }

        SecBufferDesc inbuf;
        SecBuffer inBufs[1];
        SecBufferDesc outbuf;
        SecBuffer outBufs[1];

        if (pcctx->haveCtxt) {
            // If we already have a context, we now have data to send.
            // Put this data in an inbuf.
            inbuf.ulVersion = SECBUFFER_VERSION;
            inbuf.cBuffers = 1;
            inbuf.pBuffers = inBufs;
            inBufs[0].pvBuffer = const_cast<char*>(serverin);
            inBufs[0].cbBuffer = serverinlen;
            inBufs[0].BufferType = SECBUFFER_TOKEN;
        }

        outbuf.ulVersion = SECBUFFER_VERSION;
        outbuf.cBuffers = 1;
        outbuf.pBuffers = outBufs;
        outBufs[0].pvBuffer = NULL;
        outBufs[0].cbBuffer = 0;
        outBufs[0].BufferType = SECBUFFER_TOKEN;

        ULONG contextAttr = 0;
        SECURITY_STATUS status = InitializeSecurityContextW(&pcctx->cred,
                                                            pcctx->haveCtxt ? &pcctx->ctx : NULL,
                                                            const_cast<wchar_t*>(
                                                                pcctx->nameToken.c_str()),
                                                            ISC_REQ_ALLOCATE_MEMORY |
                                                            ISC_REQ_MUTUAL_AUTH,
                                                            0,
                                                            SECURITY_NETWORK_DREP,
                                                            (pcctx->haveCtxt ? &inbuf : NULL),
                                                            0,
                                                            &pcctx->ctx,
                                                            &outbuf,
                                                            &contextAttr,
                                                            NULL);

        if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
            HandleLastError(cparams->utils, status, "InitializeSecurityContext");
            return SASL_FAIL;
        }

        ON_BLOCK_EXIT(FreeContextBuffer, outbuf.pBuffers[0].pvBuffer);
        pcctx->haveCtxt = true;

        if (status == SEC_E_OK) {
            // Send back nothing and wait for the server to reply with the security capabilities
            *clientout = NULL;
            *clientoutlen = 0;
            pcctx->authComplete = true;
            return SASL_CONTINUE;
        }

        char *newoutbuf = static_cast<char*>(cparams->utils->malloc(outBufs[0].cbBuffer));
        *clientoutlen = outBufs[0].cbBuffer;
        memcpy(newoutbuf, outBufs[0].pvBuffer, *clientoutlen);
        *clientout = newoutbuf;
        return SASL_CONTINUE;
    }
Пример #5
0
bool
NegotiateAuth::authorize(const AuthParams &challenge, AuthParams &authorization,
    const URI &uri)
{
    SECURITY_STATUS status;
    std::wstring packageW = toUtf16(challenge.scheme);
    std::string param = challenge.base64;

    std::string outboundBuffer;
    SecBufferDesc outboundBufferDesc;
    SecBuffer outboundSecBuffer;
    TimeStamp lifetime;
    ULONG contextAttributes;

    outboundBuffer.resize(4096);
    outboundBufferDesc.ulVersion = 0;
    outboundBufferDesc.cBuffers = 1;
    outboundBufferDesc.pBuffers = &outboundSecBuffer;
    outboundSecBuffer.BufferType = SECBUFFER_TOKEN;
    outboundSecBuffer.pvBuffer = &outboundBuffer[0];
    outboundSecBuffer.cbBuffer = (unsigned long)outboundBuffer.size();

    if (param.empty()) {
        // No response from server; we're starting a new session
        if (SecIsValidHandle(&m_creds))
            return false;

        SEC_WINNT_AUTH_IDENTITY_W id;
        id.User = (unsigned short *)m_username.c_str();
        id.UserLength = (unsigned long)m_username.size();
        id.Domain = (unsigned short *)m_domain.c_str();
        id.DomainLength = (unsigned long)m_domain.size();
        id.Password = (unsigned short *)m_password.c_str();
        id.PasswordLength = (unsigned long)m_password.size();
        id.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
        status = AcquireCredentialsHandleW(NULL,
            (wchar_t *)packageW.c_str(),
            SECPKG_CRED_OUTBOUND,
            NULL,
            m_username.empty() ? NULL : &id,
            NULL,
            NULL,
            &m_creds,
            &lifetime);
        MORDOR_LOG_TRACE(g_log) << "AcquireCredentialsHandleW("
            << challenge.scheme << ", " << toUtf8(m_username) << "): ("
            << status << ")";
        if (!SUCCEEDED(status))
            MORDOR_THROW_EXCEPTION_FROM_ERROR_API(status, "AcquireCredentialsHandleW");

        status = InitializeSecurityContextW(
            &m_creds,
            NULL,
            (wchar_t *)toUtf16(uri.toString()).c_str(),
            ISC_REQ_CONFIDENTIALITY,
            0,
            SECURITY_NATIVE_DREP,
            NULL,
            0,
            &m_secCtx,
            &outboundBufferDesc,
            &contextAttributes,
            &lifetime);
        MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW("
            << uri << ", {0}):  {" << outboundSecBuffer.cbBuffer << "} ("
            << status << ")";
    } else {
        // Prepare the response from the server
        std::string inboundBuffer = base64decode(param);
        SecBufferDesc inboundBufferDesc;
        SecBuffer inboundSecBuffer;

        inboundBufferDesc.ulVersion = 0;
        inboundBufferDesc.cBuffers = 1;
        inboundBufferDesc.pBuffers = &inboundSecBuffer;
        inboundSecBuffer.BufferType = SECBUFFER_TOKEN;
        inboundSecBuffer.pvBuffer = &inboundBuffer[0];
        inboundSecBuffer.cbBuffer = (unsigned long)inboundBuffer.size();

        status = InitializeSecurityContextW(
            &m_creds,
            &m_secCtx,
            (wchar_t *)toUtf16(uri.toString()).c_str(),
            ISC_REQ_CONFIDENTIALITY,
            0,
            SECURITY_NATIVE_DREP,
            &inboundBufferDesc,
            0,
            &m_secCtx,
            &outboundBufferDesc,
            &contextAttributes,
            &lifetime);
        MORDOR_LOG_TRACE(g_log) << "InitializeSecurityContextW("
            << uri << ", {" << inboundSecBuffer.cbBuffer << "}):  {"
            << outboundSecBuffer.cbBuffer << "} (" << status << ")";
    }

    if (status == SEC_I_COMPLETE_NEEDED ||
        status == SEC_I_COMPLETE_AND_CONTINUE) {
        status = CompleteAuthToken(&m_secCtx, &outboundBufferDesc);
        MORDOR_LOG_TRACE(g_log) << "CompleteAuthToken(): {"
            << outboundSecBuffer.cbBuffer << "} (" << status << ")";
    }

    if (!SUCCEEDED(status))
        MORDOR_THROW_EXCEPTION_FROM_ERROR(status);

    outboundBuffer.resize(outboundSecBuffer.cbBuffer);
    authorization.scheme = challenge.scheme;
    authorization.base64 = base64encode(outboundBuffer);
    authorization.parameters.clear();
    return true;
}