mirror of
https://github.com/valitydev/osquery-1.git
synced 2024-11-07 18:08:53 +00:00
add feature to select multiple rows to signature table
This commit is contained in:
parent
4609486f74
commit
0706146c01
@ -91,93 +91,94 @@ void genSignatureForFile(const std::string& path, QueryData& results) {
|
||||
}
|
||||
|
||||
// Actually validate.
|
||||
bool isValidated = false;
|
||||
result =
|
||||
SecStaticCodeCheckValidityWithErrors(staticCode, flags, nullptr, nullptr);
|
||||
if (result == errSecSuccess) {
|
||||
CFDictionaryRef codeInfo = nullptr;
|
||||
|
||||
result = SecCodeCopySigningInformation(
|
||||
staticCode, kSecCSSigningInformation | kSecCSRequirementInformation,
|
||||
&codeInfo);
|
||||
if (result == errSecSuccess) {
|
||||
// If we don't get an identifier for this file, then it's not signed.
|
||||
CFStringRef ident =
|
||||
(CFStringRef)CFDictionaryGetValue(codeInfo, kSecCodeInfoIdentifier);
|
||||
if (ident != nullptr) {
|
||||
// We have an identifier - this indicates that the file is signed,
|
||||
// and, since it didn't error above, it's *also* a valid signature.
|
||||
r["signed"] = INTEGER(1);
|
||||
r["identifier"] = stringFromCFString(ident);
|
||||
|
||||
// Get CDHash
|
||||
r["cdhash"] = "";
|
||||
CFTypeRef hashInfo = CFDictionaryGetValue(codeInfo, kSecCodeInfoUnique);
|
||||
if (hashInfo != nullptr) {
|
||||
r["cdhash"].reserve(CC_SHA1_DIGEST_LENGTH);
|
||||
// Get the SHA-1 bytes
|
||||
std::stringstream ss;
|
||||
auto bytes = CFDataGetBytePtr((CFDataRef)hashInfo);
|
||||
if (bytes != nullptr) {
|
||||
// Write bytes as hex strings
|
||||
for (unsigned n = 0; n < CC_SHA1_DIGEST_LENGTH; n++) {
|
||||
ss << std::hex << std::setfill('0') << std::setw(2);
|
||||
ss << (unsigned int)bytes[n];
|
||||
}
|
||||
r["cdhash"] = ss.str();
|
||||
}
|
||||
if (r["cdhash"].length() != CC_SHA1_DIGEST_LENGTH * 2) {
|
||||
VLOG(1) << "Error extracting code directory hash";
|
||||
r["cdhash"] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Team Identifier
|
||||
r["team_identifier"] = "";
|
||||
CFTypeRef teamIdent = nullptr;
|
||||
if (CFDictionaryGetValueIfPresent(codeInfo, kSecCodeInfoTeamIdentifier,
|
||||
&teamIdent)) {
|
||||
r["team_identifier"] = stringFromCFString((CFStringRef)teamIdent);
|
||||
}
|
||||
|
||||
// Get common name
|
||||
r["authority"] = "";
|
||||
CFArrayRef certChain = (CFArrayRef)CFDictionaryGetValue(
|
||||
codeInfo, kSecCodeInfoCertificates);
|
||||
if (certChain != nullptr) {
|
||||
CFIndex count = CFArrayGetCount(certChain);
|
||||
// Only look at the first cert, which is the developer's cert
|
||||
if (count > 0) {
|
||||
auto cert = SecCertificateRef(CFArrayGetValueAtIndex(certChain, 0));
|
||||
auto der_encoded_data = SecCertificateCopyData(cert);
|
||||
if (der_encoded_data != nullptr) {
|
||||
auto der_bytes = CFDataGetBytePtr(der_encoded_data);
|
||||
auto length = CFDataGetLength(der_encoded_data);
|
||||
auto x509_cert = d2i_X509(nullptr, &der_bytes, length);
|
||||
if (x509_cert != nullptr) {
|
||||
std::string subject;
|
||||
std::string issuer;
|
||||
std::string commonName;
|
||||
genCommonName(x509_cert, subject, commonName, issuer);
|
||||
r["authority"] = commonName;
|
||||
X509_free(x509_cert);
|
||||
} else {
|
||||
VLOG(1) << "Error decoding DER encoded certificate";
|
||||
}
|
||||
CFRelease(der_encoded_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VLOG(1) << "No identifier found for file: " << path;
|
||||
}
|
||||
CFRelease(codeInfo);
|
||||
} else {
|
||||
VLOG(1) << "Could not get signing information for file: " << path;
|
||||
}
|
||||
isValidated = true;
|
||||
} else {
|
||||
// If this errors, then we either don't have a signature, or it's malformed.
|
||||
VLOG(1) << "Static code validity check failed for file: " << path;
|
||||
}
|
||||
CFDictionaryRef codeInfo = nullptr;
|
||||
result = SecCodeCopySigningInformation(
|
||||
staticCode, kSecCSSigningInformation | kSecCSRequirementInformation,
|
||||
&codeInfo);
|
||||
if (result == errSecSuccess) {
|
||||
// If we don't get an identifier for this file, then it's not signed.
|
||||
CFStringRef ident =
|
||||
(CFStringRef)CFDictionaryGetValue(codeInfo, kSecCodeInfoIdentifier);
|
||||
if (ident != nullptr) {
|
||||
// We have an identifier - this indicates that the file is signed,
|
||||
// and, since it didn't error above, it's *also* a valid signature.
|
||||
if (isValidated) {
|
||||
r["signed"] = INTEGER(1);
|
||||
}
|
||||
r["identifier"] = stringFromCFString(ident);
|
||||
|
||||
// Get CDHash
|
||||
r["cdhash"] = "";
|
||||
CFDataRef hashInfo =
|
||||
(CFDataRef)CFDictionaryGetValue(codeInfo, kSecCodeInfoUnique);
|
||||
if (hashInfo != nullptr) {
|
||||
r["cdhash"].reserve(CC_SHA1_DIGEST_LENGTH);
|
||||
// Get the SHA-1 bytes
|
||||
std::stringstream ss;
|
||||
auto bytes = CFDataGetBytePtr(hashInfo);
|
||||
if (bytes != nullptr &&
|
||||
CFDataGetLength(hashInfo) == CC_SHA1_DIGEST_LENGTH) {
|
||||
// Write bytes as hex strings
|
||||
for (size_t n = 0; n < CC_SHA1_DIGEST_LENGTH; n++) {
|
||||
ss << std::hex << std::setfill('0') << std::setw(2);
|
||||
ss << (unsigned int)bytes[n];
|
||||
}
|
||||
r["cdhash"] = ss.str();
|
||||
}
|
||||
if (r["cdhash"].length() != CC_SHA1_DIGEST_LENGTH * 2) {
|
||||
VLOG(1) << "Error extracting code directory hash";
|
||||
r["cdhash"] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Team Identifier
|
||||
r["team_identifier"] = "";
|
||||
CFTypeRef teamIdent = nullptr;
|
||||
if (CFDictionaryGetValueIfPresent(codeInfo, kSecCodeInfoTeamIdentifier,
|
||||
&teamIdent)) {
|
||||
r["team_identifier"] = stringFromCFString((CFStringRef)teamIdent);
|
||||
}
|
||||
|
||||
// Get common name
|
||||
r["authority"] = "";
|
||||
CFArrayRef certChain =
|
||||
(CFArrayRef)CFDictionaryGetValue(codeInfo, kSecCodeInfoCertificates);
|
||||
if (certChain != nullptr && CFArrayGetCount(certChain) > 0) {
|
||||
auto cert = SecCertificateRef(CFArrayGetValueAtIndex(certChain, 0));
|
||||
auto der_encoded_data = SecCertificateCopyData(cert);
|
||||
if (der_encoded_data != nullptr) {
|
||||
auto der_bytes = CFDataGetBytePtr(der_encoded_data);
|
||||
auto length = CFDataGetLength(der_encoded_data);
|
||||
auto x509_cert = d2i_X509(nullptr, &der_bytes, length);
|
||||
if (x509_cert != nullptr) {
|
||||
std::string subject;
|
||||
std::string issuer;
|
||||
std::string commonName;
|
||||
genCommonName(x509_cert, subject, commonName, issuer);
|
||||
r["authority"] = commonName;
|
||||
X509_free(x509_cert);
|
||||
} else {
|
||||
VLOG(1) << "Error decoding DER encoded certificate";
|
||||
}
|
||||
CFRelease(der_encoded_data);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VLOG(1) << "No identifier found for file: " << path;
|
||||
}
|
||||
CFRelease(codeInfo);
|
||||
} else {
|
||||
VLOG(1) << "Could not get signing information for file: " << path;
|
||||
}
|
||||
|
||||
results.push_back(r);
|
||||
CFRelease(staticCode);
|
||||
@ -190,6 +191,19 @@ QueryData genSignature(QueryContext& context) {
|
||||
// directory. We search for the parsed predicate constraints with the equals
|
||||
// operator.
|
||||
auto paths = context.constraints["path"].getAll(EQUALS);
|
||||
context.expandConstraints(
|
||||
"path", LIKE, paths,
|
||||
([&](const std::string& pattern, std::set<std::string>& out) {
|
||||
std::vector<std::string> patterns;
|
||||
auto status =
|
||||
resolveFilePattern(pattern, patterns, GLOB_ALL | GLOB_NO_CANON);
|
||||
if (status.ok()) {
|
||||
for (const auto& resolved : patterns) {
|
||||
out.insert(resolved);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}));
|
||||
for (const auto& path_string : paths) {
|
||||
// Note: we are explicitly *not* using is_regular_file here, since you can
|
||||
// pass a directory path to the verification functions (e.g. for app
|
||||
|
@ -76,11 +76,14 @@ TEST_F(SignatureTest, test_get_valid_signature) {
|
||||
{"path", path},
|
||||
{"signed", "1"},
|
||||
{"identifier", "com.apple.ls"},
|
||||
{"authority", "Software Signing"},
|
||||
};
|
||||
|
||||
for (const auto& column : expected) {
|
||||
EXPECT_EQ(results.front()[column.first], column.second);
|
||||
}
|
||||
ASSERT_TRUE(results.front()["team_identifier"].length() >= 0);
|
||||
ASSERT_TRUE(results.front()["cdhash"].length() > 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -99,6 +102,9 @@ TEST_F(SignatureTest, test_get_unsigned) {
|
||||
{"path", path},
|
||||
{"signed", "0"},
|
||||
{"identifier", ""},
|
||||
{"cdhash", ""},
|
||||
{"team_identifier", ""},
|
||||
{"authority", ""},
|
||||
};
|
||||
|
||||
for (const auto& column : expected) {
|
||||
@ -149,12 +155,15 @@ TEST_F(SignatureTest, test_get_invalid_signature) {
|
||||
Row expected = {
|
||||
{"path", newPath},
|
||||
{"signed", "0"},
|
||||
{"identifier", ""},
|
||||
{"identifier", "com.apple.ls"},
|
||||
{"authority", "Software Signing"},
|
||||
};
|
||||
|
||||
for (const auto& column : expected) {
|
||||
EXPECT_EQ(results.front()[column.first], column.second);
|
||||
}
|
||||
ASSERT_TRUE(results.front()["team_identifier"].length() >= 0);
|
||||
ASSERT_TRUE(results.front()["cdhash"].length() > 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user