Skip to content

Commit

Permalink
[ssl] Support Windows system roots. (grpc#34874)
Browse files Browse the repository at this point in the history
This PR is copied from grpc#34276, since I did not have permissions to add commits to it. That PR has been verified to work (see the top-level description). This PR just makes the gRPC tests pass (e.g. adding includes, clang formatting).

Closes grpc#34874

COPYBARA_INTEGRATE_REVIEW=grpc#34874 from matthewstevenson88:pull_34276 d5fb73e
PiperOrigin-RevId: 609107146
  • Loading branch information
matthewstevenson88 authored and copybara-github committed Feb 21, 2024
1 parent d54074c commit 51bccbd
Show file tree
Hide file tree
Showing 19 changed files with 134 additions and 6 deletions.
1 change: 1 addition & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -3723,6 +3723,7 @@ grpc_cc_library(
"//src/core:lib/security/credentials/tls/tls_utils.cc",
"//src/core:lib/security/security_connector/load_system_roots_fallback.cc",
"//src/core:lib/security/security_connector/load_system_roots_supported.cc",
"//src/core:lib/security/security_connector/load_system_roots_windows.cc",
"//src/core:lib/security/util/json_util.cc",
],
hdrs = [
Expand Down
3 changes: 3 additions & 0 deletions CMakeLists.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Makefile

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Package.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions build_autogenerated.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions config.m4

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions config.w32

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions gRPC-Core.podspec

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions grpc.gemspec

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions grpc.gyp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/core/lib/security/security_connector/load_system_roots.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@

namespace grpc_core {

// TODO(matthewstevenson88): Update LoadSystemRootCerts to use Slice
// instead of grpc_slice.

// Returns a slice containing roots from the OS trust store
grpc_slice LoadSystemRootCerts();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include <grpc/support/port_platform.h>

#if !defined(GPR_LINUX) && !defined(GPR_ANDROID) && !defined(GPR_FREEBSD) && \
!defined(GPR_APPLE)
!defined(GPR_APPLE) && !defined(GPR_WINDOWS)

#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
Expand All @@ -32,4 +32,5 @@ grpc_slice LoadSystemRootCerts() { return grpc_empty_slice(); }

} // namespace grpc_core

#endif // !(GPR_LINUX || GPR_ANDROID || GPR_FREEBSD || GPR_APPLE)
#endif // !(GPR_LINUX || GPR_ANDROID || GPR_FREEBSD || GPR_APPLE ||
// GPR_WINDOWS)
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
//
// Copyright 2023 gRPC authors.
//
// 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.
//
//

#include <grpc/support/port_platform.h>

#if defined(GPR_WINDOWS)

#pragma comment(lib, "crypt32")

#include <esent.h>
#include <wincrypt.h>

#include <vector>

#include <grpc/slice.h>
#include <grpc/slice_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/security/security_connector/load_system_roots.h"
#include "src/core/lib/slice/slice_internal.h"

namespace grpc_core {
namespace {

std::string Utf8Encode(const std::wstring& wstr) {
if (wstr.empty()) return "";

int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(),
NULL, 0, NULL, NULL);
std::string str_to(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str_to[0],
size_needed, NULL, NULL);
return str_to;
}

} // namespace

grpc_slice LoadSystemRootCerts() {
std::string bundle_string;

// Open root certificate store.
HANDLE root_cert_store = CertOpenSystemStoreW(NULL, L"ROOT");
if (!root_cert_store) {
return grpc_empty_slice();
}

// Load all root certificates from certificate store.
PCCERT_CONTEXT cert = NULL;
while ((cert = CertEnumCertificatesInStore(root_cert_store, cert)) != NULL) {
// Append each certificate in PEM format.
DWORD size = 0;
CryptBinaryToStringW(cert->pbCertEncoded, cert->cbCertEncoded,
CRYPT_STRING_BASE64HEADER, NULL, &size);
std::vector<WCHAR> pem(size);
CryptBinaryToStringW(cert->pbCertEncoded, cert->cbCertEncoded,
CRYPT_STRING_BASE64HEADER, pem.data(), &size);
bundle_string += Utf8Encode(pem.data());
}

CertCloseStore(root_cert_store, 0);
if (bundle_string.size() == 0) {
return grpc_empty_slice();
}

return grpc_slice_from_cpp_string(std::move(bundle_string));
}

} // namespace grpc_core

#endif // GPR_WINDOWS
1 change: 1 addition & 0 deletions src/python/grpcio/grpc_core_dependencies.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion templates/Makefile.template
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@
endif

ifeq ($(SYSTEM),MINGW32)
LIBS = m pthread ws2_32 iphlpapi dbghelp bcrypt
LIBS = m pthread ws2_32 crypt32 iphlpapi dbghelp bcrypt
LDFLAGS += -pthread
endif

Expand Down
20 changes: 18 additions & 2 deletions test/core/security/system_roots_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@

#include <stdio.h>

#if defined(GPR_LINUX) || defined(GPR_FREEBSD) || defined(GPR_APPLE)
#if defined(GPR_LINUX) || defined(GPR_FREEBSD) || defined(GPR_APPLE) || \
defined(GPR_WINDOWS)
#include <string.h>
#if defined(GPR_LINUX) || defined(GPR_FREEBSD) || defined(GPR_APPLE)
#include <sys/param.h>
#endif // GPR_LINUX || GPR_FREEBSD || GPR_APPLE

#include "gtest/gtest.h"

Expand All @@ -48,6 +51,10 @@
namespace grpc {
namespace {

// The GetAbsoluteFilePath and CreateRootCertsBundle helper functions are only
// defined on some platforms. On other platforms (e.g. Windows), we rely on
// built-in helper functions to play similar (but not exactly the same) roles.
#if defined(GPR_LINUX) || defined(GPR_FREEBSD) || defined(GPR_APPLE)
TEST(AbsoluteFilePathTest, ConcatenatesCorrectly) {
const char* directory = "nonexistent/test/directory";
const char* filename = "doesnotexist.txt";
Expand Down Expand Up @@ -80,6 +87,15 @@ TEST(CreateRootCertsBundleTest, BundlesCorrectly) {
<< "Expected: \"" << result_slice.as_string_view() << "\"\n"
<< "Actual: \"" << roots_bundle_str << "\"";
}
#endif // GPR_LINUX || GPR_FREEBSD || GPR_APPLE

#if defined(GPR_WINDOWS)
TEST(LoadSystemRootCertsTest, Success) {
grpc_slice roots_slice = grpc_core::LoadSystemRootCerts();
EXPECT_FALSE(GRPC_SLICE_IS_EMPTY(roots_slice));
grpc_slice_unref(roots_slice);
}
#endif // GPR_WINDOWS

} // namespace
} // namespace grpc
Expand All @@ -96,4 +112,4 @@ int main() {
"systems ***\n");
return 0;
}
#endif // GPR_LINUX || GPR_FREEBSD || GPR_APPLE
#endif // GPR_LINUX || GPR_FREEBSD || GPR_APPLE || GPR_WINDOWS
1 change: 1 addition & 0 deletions tools/doxygen/Doxyfile.c++.internal

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tools/doxygen/Doxyfile.core.internal

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 51bccbd

Please sign in to comment.