add feature to select multiple rows to signature table

This commit is contained in:
Sereyvathana Ty 2016-03-18 22:29:20 -07:00
parent 4609486f74
commit 0706146c01
2 changed files with 104 additions and 81 deletions

View File

@ -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

View File

@ -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);
}
}