kmscng/util/registration.cc (96 lines of code) (raw):
// Copyright 2023 Google LLC
//
// 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 "kmscng/util/registration.h"
#include <iostream>
#include "absl/strings/str_format.h"
#include "kmscng/cng_headers.h"
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
namespace cloud_kms::kmscng {
absl::Status RegisterProvider() {
NTSTATUS status = 0;
PWSTR algorithms[1] = {const_cast<wchar_t*>(NCRYPT_KEY_STORAGE_ALGORITHM)};
CRYPT_INTERFACE_REG algorithm_class = {
NCRYPT_KEY_STORAGE_INTERFACE, // Ncrypt key storage interface
CRYPT_LOCAL, // Scope: local system only
1, // Algorithms count
algorithms // Name(s) of the algorithm(s)
};
PCRYPT_INTERFACE_REG algorithm_classes[1] = {&algorithm_class};
CRYPT_IMAGE_REG ksp_image = {
const_cast<wchar_t*>(
kProviderDllName.data()), // File name of the KSP binary
1, // Number of algorithm classes the binary supports
algorithm_classes // List of all algorithm classes available
};
CRYPT_PROVIDER_REG ksp_provider = {
0, // Aliases
NULL, // Names of aliases
&ksp_image, // Image that provides user-mode support
NULL // Image that provides kernel-mode support (*MUST* be NULL)
};
// Register our custom CNG provider
status =
BCryptRegisterProvider(kProviderName.data(),
CRYPT_OVERWRITE, // overwrite an existing entry
&ksp_provider);
if (!NT_SUCCESS(status)) {
return absl::InternalError(absl::StrFormat(
"BCryptRegisterProvider failed with error code 0x%08x\n", status));
}
// Add the algorithm name to the priority list of the key storage algorithm
// class. (This makes it visible to BCryptResolveProviders.)
status =
BCryptAddContextFunction(CRYPT_LOCAL, // Scope: local machine only
NULL, // Application context: default
NCRYPT_KEY_STORAGE_INTERFACE, // Algorithm class
NCRYPT_KEY_STORAGE_ALGORITHM, // Algorithm name
CRYPT_PRIORITY_BOTTOM // Lowest priority
);
if (!NT_SUCCESS(status)) {
return absl::InternalError(absl::StrFormat(
"BCryptAddContextFunction failed with error code 0x%08x\n", status));
}
// Identify our provider as an implementation of the key storage interface.
status = BCryptAddContextFunctionProvider(
CRYPT_LOCAL, // Scope: local machine only
NULL, // Application context: default
NCRYPT_KEY_STORAGE_INTERFACE, // Algorithm class
NCRYPT_KEY_STORAGE_ALGORITHM, // Algorithm name
kProviderName.data(), // Provider name
CRYPT_PRIORITY_BOTTOM // Lowest priority
);
if (!NT_SUCCESS(status)) {
return absl::InternalError(absl::StrFormat(
"BCryptAddContextFunctionProvider failed with error code 0x%08x\n",
status));
}
return absl::OkStatus();
}
absl::Status UnregisterProvider() {
NTSTATUS status = 0;
// Tell CNG that this provider no longer supports the algorithm.
status = BCryptRemoveContextFunctionProvider(
CRYPT_LOCAL, // Scope: local machine only
NULL, // Application context: default
NCRYPT_KEY_STORAGE_INTERFACE, // Algorithm class
NCRYPT_KEY_STORAGE_ALGORITHM, // Algorithm name
kProviderName.data() // Provider name
);
if (!NT_SUCCESS(status)) {
return absl::InternalError(absl::StrFormat(
"BCryptRemoveContextFunctionProvider failed with error code 0x%08x\n",
status));
}
// Drop the provider from the CNG priority list.
status = BCryptRemoveContextFunction(
CRYPT_LOCAL, // Scope: local machine only
NULL, // Application context: default
NCRYPT_KEY_STORAGE_INTERFACE, // Algorithm class
NCRYPT_KEY_STORAGE_ALGORITHM // Algorithm name
);
if (!NT_SUCCESS(status)) {
return absl::InternalError(absl::StrFormat(
"BCryptRemoveContextFunction failed with error code 0x%08x\n", status));
}
// Unregister our custom CNG provider.
status = BCryptUnregisterProvider(kProviderName.data());
if (!NT_SUCCESS(status)) {
return absl::InternalError(absl::StrFormat(
"BCryptUnregisterProvider failed with error code 0x%08x\n", status));
}
return absl::OkStatus();
}
} // namespace cloud_kms::kmscng