blob: f2564dc5f58fb0eae55b3938c5fee22bf3ab4396 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 <openssl/x509v3.h>
#include "utils/gsl.h"
#include "utils/tls/ExtendedKeyUsage.h"
#include "unit/Catch.h"
namespace utils = org::apache::nifi::minifi::utils;
namespace {
constexpr unsigned char SEQUENCE_TAG = 0x30;
constexpr unsigned char OID_TAG = 6;
constexpr unsigned char OID_LENGTH = 8;
constexpr unsigned char OID_ENCODED_LENGTH = 2 + OID_LENGTH;
constexpr std::array<unsigned char, OID_LENGTH - 1> OID_PREFIX{0x2b, 6, 1, 5, 5, 7, 3};
// {2, 1} -> {30 14 6 8 2b 6 1 5 5 7 3 2 6 8 2b 6 1 5 5 7 3 1}
// ^---^ sequence tag + length
// ^-^ ^-^ OID tag + length
// ^-client auth--^ ^-server auth--^
std::vector<unsigned char> createDerEncodedExtendedKeyUsage(const std::vector<uint8_t>& last_bytes_of_oids) {
size_t oids_size = OID_ENCODED_LENGTH * last_bytes_of_oids.size();
std::vector<unsigned char> der_encoded_key_usage(2 + oids_size);
der_encoded_key_usage[0] = SEQUENCE_TAG;
der_encoded_key_usage[1] = gsl::narrow<unsigned char>(oids_size);
for (size_t i = 0; i < last_bytes_of_oids.size(); ++i) {
der_encoded_key_usage[2 + OID_ENCODED_LENGTH * i] = OID_TAG;
der_encoded_key_usage[3 + OID_ENCODED_LENGTH * i] = OID_LENGTH;
for (size_t j = 0; j < OID_PREFIX.size(); ++j) {
der_encoded_key_usage[4 + j + OID_ENCODED_LENGTH * i] = OID_PREFIX[j];
}
der_encoded_key_usage[4 + OID_PREFIX.size() + OID_ENCODED_LENGTH * i] = last_bytes_of_oids[i];
}
return der_encoded_key_usage;
}
utils::tls::EXTENDED_KEY_USAGE_unique_ptr createExtendedKeyUsage(const std::vector<uint8_t>& last_bytes_of_oids) {
std::vector<unsigned char> der_encoded_key_usage = createDerEncodedExtendedKeyUsage(last_bytes_of_oids);
const unsigned char* data = der_encoded_key_usage.data();
long length = gsl::narrow<long>(der_encoded_key_usage.size()); // NOLINT: cpplint hates `long`, but that is the param type in the API
utils::tls::EXTENDED_KEY_USAGE_unique_ptr key_usage{d2i_EXTENDED_KEY_USAGE(nullptr, &data, length)};
return key_usage;
}
void testIsSubsetOf(
const utils::tls::ExtendedKeyUsage key_usage_empty,
const utils::tls::ExtendedKeyUsage key_usage_clientauth,
const utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth,
const utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth_codesigning,
const utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth_timestamping) {
REQUIRE(key_usage_empty.isSubsetOf(key_usage_empty));
REQUIRE(key_usage_empty.isSubsetOf(key_usage_clientauth));
REQUIRE(key_usage_empty.isSubsetOf(key_usage_clientauth_serverauth));
REQUIRE(key_usage_empty.isSubsetOf(key_usage_clientauth_serverauth_codesigning));
REQUIRE(key_usage_empty.isSubsetOf(key_usage_clientauth_serverauth_timestamping));
REQUIRE_FALSE(key_usage_clientauth.isSubsetOf(key_usage_empty));
REQUIRE(key_usage_clientauth.isSubsetOf(key_usage_clientauth));
REQUIRE(key_usage_clientauth.isSubsetOf(key_usage_clientauth_serverauth));
REQUIRE(key_usage_clientauth.isSubsetOf(key_usage_clientauth_serverauth_codesigning));
REQUIRE(key_usage_clientauth.isSubsetOf(key_usage_clientauth_serverauth_timestamping));
REQUIRE_FALSE(key_usage_clientauth_serverauth.isSubsetOf(key_usage_empty));
REQUIRE_FALSE(key_usage_clientauth_serverauth.isSubsetOf(key_usage_clientauth));
REQUIRE(key_usage_clientauth_serverauth.isSubsetOf(key_usage_clientauth_serverauth));
REQUIRE(key_usage_clientauth_serverauth.isSubsetOf(key_usage_clientauth_serverauth_codesigning));
REQUIRE(key_usage_clientauth_serverauth.isSubsetOf(key_usage_clientauth_serverauth_timestamping));
REQUIRE_FALSE(key_usage_clientauth_serverauth_codesigning.isSubsetOf(key_usage_empty));
REQUIRE_FALSE(key_usage_clientauth_serverauth_codesigning.isSubsetOf(key_usage_clientauth));
REQUIRE_FALSE(key_usage_clientauth_serverauth_codesigning.isSubsetOf(key_usage_clientauth_serverauth));
REQUIRE(key_usage_clientauth_serverauth_codesigning.isSubsetOf(key_usage_clientauth_serverauth_codesigning));
REQUIRE_FALSE(key_usage_clientauth_serverauth_codesigning.isSubsetOf(key_usage_clientauth_serverauth_timestamping));
REQUIRE_FALSE(key_usage_clientauth_serverauth_timestamping.isSubsetOf(key_usage_empty));
REQUIRE_FALSE(key_usage_clientauth_serverauth_timestamping.isSubsetOf(key_usage_clientauth));
REQUIRE_FALSE(key_usage_clientauth_serverauth_timestamping.isSubsetOf(key_usage_clientauth_serverauth));
REQUIRE_FALSE(key_usage_clientauth_serverauth_timestamping.isSubsetOf(key_usage_clientauth_serverauth_codesigning));
REQUIRE(key_usage_clientauth_serverauth_timestamping.isSubsetOf(key_usage_clientauth_serverauth_timestamping));
}
} // namespace
TEST_CASE("ExtendedKeyUsage can be created from an ASN.1 structure", "[constructor][isSubsetOf]") {
utils::tls::EXTENDED_KEY_USAGE_unique_ptr key_usage_ptr_empty = createExtendedKeyUsage({});
utils::tls::EXTENDED_KEY_USAGE_unique_ptr key_usage_ptr_clientauth = createExtendedKeyUsage({2});
utils::tls::EXTENDED_KEY_USAGE_unique_ptr key_usage_ptr_clientauth_serverauth = createExtendedKeyUsage({2, 1});
utils::tls::EXTENDED_KEY_USAGE_unique_ptr key_usage_ptr_clientauth_serverauth_codesigning = createExtendedKeyUsage({2, 1, 3});
utils::tls::EXTENDED_KEY_USAGE_unique_ptr key_usage_ptr_clientauth_serverauth_timestamping = createExtendedKeyUsage({2, 1, 8});
utils::tls::ExtendedKeyUsage key_usage_empty{*key_usage_ptr_empty};
utils::tls::ExtendedKeyUsage key_usage_clientauth{*key_usage_ptr_clientauth};
utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth{*key_usage_ptr_clientauth_serverauth};
utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth_codesigning{*key_usage_ptr_clientauth_serverauth_codesigning};
utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth_timestamping{*key_usage_ptr_clientauth_serverauth_timestamping};
testIsSubsetOf(key_usage_empty,
key_usage_clientauth,
key_usage_clientauth_serverauth,
key_usage_clientauth_serverauth_codesigning,
key_usage_clientauth_serverauth_timestamping);
}
TEST_CASE("ExtendedKeyUsage can be created from list of usage strings", "[constructor][isSubsetOf]") {
constexpr const char* key_usage_str_empty = "";
constexpr const char* key_usage_str_clientauth = "Client Authentication";
constexpr const char* key_usage_str_clientauth_serverauth = "Client Authentication, Server Authentication";
constexpr const char* key_usage_str_clientauth_serverauth_codesigning = "Server Authentication, Client Authentication,Code Signing";
constexpr const char* key_usage_str_clientauth_serverauth_timestamping = "\tClient Authentication , Time Stamping\t,\tServer Authentication\r";
utils::tls::ExtendedKeyUsage key_usage_empty{key_usage_str_empty};
utils::tls::ExtendedKeyUsage key_usage_clientauth{key_usage_str_clientauth};
utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth{key_usage_str_clientauth_serverauth};
utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth_codesigning{key_usage_str_clientauth_serverauth_codesigning};
utils::tls::ExtendedKeyUsage key_usage_clientauth_serverauth_timestamping{key_usage_str_clientauth_serverauth_timestamping};
testIsSubsetOf(key_usage_empty,
key_usage_clientauth,
key_usage_clientauth_serverauth,
key_usage_clientauth_serverauth_codesigning,
key_usage_clientauth_serverauth_timestamping);
}
TEST_CASE("ExtendedKeyUsage created from ASN.1 and string are identical", "[constructor][equal]") {
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({})} == utils::tls::ExtendedKeyUsage{""});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({2})} == utils::tls::ExtendedKeyUsage{"Client Authentication"});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 2})} == utils::tls::ExtendedKeyUsage{"Client Authentication, Server Authentication"});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 2, 4})} == utils::tls::ExtendedKeyUsage{"Client Authentication, Server Authentication, Secure Email"});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({8, 9})} == utils::tls::ExtendedKeyUsage{"Time Stamping, OCSP Signing"});
}
TEST_CASE("ExtendedKeyUsage objects with the same flags in a different order are equal", "[constructor][equal]") {
REQUIRE(utils::tls::ExtendedKeyUsage{"Server Authentication, Client Authentication"} == utils::tls::ExtendedKeyUsage{"Client Authentication, Server Authentication"});
utils::tls::ExtendedKeyUsage key_usage_123{"Server Authentication, Client Authentication, Code Signing"};
utils::tls::ExtendedKeyUsage key_usage_132{"Server Authentication, Code Signing, Client Authentication"};
utils::tls::ExtendedKeyUsage key_usage_213{"Client Authentication, Server Authentication, Code Signing"};
utils::tls::ExtendedKeyUsage key_usage_231{"Client Authentication, Code Signing, Server Authentication"};
utils::tls::ExtendedKeyUsage key_usage_312{"Code Signing, Server Authentication, Client Authentication"};
utils::tls::ExtendedKeyUsage key_usage_321{"Code Signing, Client Authentication, Server Authentication"};
REQUIRE(key_usage_123 == key_usage_132);
REQUIRE(key_usage_123 == key_usage_213);
REQUIRE(key_usage_123 == key_usage_231);
REQUIRE(key_usage_123 == key_usage_312);
REQUIRE(key_usage_123 == key_usage_321);
}
TEST_CASE("ExtendedKeyUsage objects with different flags are different", "[constructor][not_equal]") {
REQUIRE(utils::tls::ExtendedKeyUsage{""} != utils::tls::ExtendedKeyUsage{"Client Authentication"});
REQUIRE(utils::tls::ExtendedKeyUsage{"Client Authentication"} != utils::tls::ExtendedKeyUsage{"Client Authentication, Server Authentication"});
REQUIRE(utils::tls::ExtendedKeyUsage{"Client Authentication"} != utils::tls::ExtendedKeyUsage{"Code Signing"});
}
TEST_CASE("ExtendedKeyUsage ignores unrecognized string flags", "[constructor]") {
REQUIRE(utils::tls::ExtendedKeyUsage{""} == utils::tls::ExtendedKeyUsage{"Rubik's Cube Shuffling"});
REQUIRE(utils::tls::ExtendedKeyUsage{"Client Authentication"} == utils::tls::ExtendedKeyUsage{"Client Authentication, Client Onboarding"});
REQUIRE(utils::tls::ExtendedKeyUsage{"Client Authentication, Server Authentication"} == utils::tls::ExtendedKeyUsage{"User Authentication, Server Authentication, Client Authentication"});
}
TEST_CASE("ExtendedKeyUsage can set unrecognized ASN.1 flags", "[constructor]") {
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({})} != utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({10})});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1})} != utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 12})});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 2})} != utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 2, 15})});
}
TEST_CASE("ExtendedKeyUsage ignores ASN.1 flags higher than 15", "[constructor]") {
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({})} == utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({16})});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1})} == utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 100})});
REQUIRE(utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 2})} == utils::tls::ExtendedKeyUsage{*createExtendedKeyUsage({1, 2, 127})});
// values with the first bit set cause an error:
REQUIRE(createExtendedKeyUsage({128}) == nullptr);
REQUIRE(createExtendedKeyUsage({1, 2, 200}) == nullptr);
}