// SPDX-License-Identifier: MIT
// apps/src/dso-verify.cpp
//
// dso-verify — verify a signed DSO and report trust level
//
// Usage:
// dso-verify addon.so
// dso-verify addon.so --keys /etc/myapp/trusted-keys.d/
// dso-verify addon.so --keys /etc/myapp/trusted-keys.d/ --quiet
//
// Exit codes:
// 0 TRUSTED — valid signature, signer key in trusted-keys directory
// 1 UNKNOWN — valid signature, signer key NOT in trusted-keys directory
// 2 UNSIGNED — no manifest/signature sections
// 3 REJECTED — signature invalid or SHA-256 mismatch
// 4 ERROR — I/O or format error
#include <sign/Verifier.hh>
#include <sign/TrustLevel.hh>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace fedem::sign;
int main( int argc, char** argv )
{
std::string dsoPath, keysDir;
bool quiet = false;
for( int i = 1; i < argc; ++i )
{
if( !std::strcmp(argv[i],"--keys") && i+1<argc ) keysDir = argv[++i];
else if( !std::strcmp(argv[i],"--quiet") || !std::strcmp(argv[i],"-q") ) quiet = true;
else if( !std::strcmp(argv[i],"--help") || !std::strcmp(argv[i],"-h") )
{
std::puts("Usage: dso-verify <addon.so> [--keys <trusted-keys.d/>] [--quiet]\n"
"Exit: 0=TRUSTED 1=UNKNOWN 2=UNSIGNED 3=REJECTED 4=ERROR");
return 0;
}
else if( argv[i][0] != '-' ) dsoPath = argv[i];
else { std::fprintf(stderr,"error: unknown argument: %s\n",argv[i]); return 4; }
}
if( dsoPath.empty() )
{ std::fputs("error: DSO path required\n",stderr); return 4; }
// Default trusted-keys search order
std::string const keysSearch = keysDir.empty() ? "/etc/trusted-keys.d" : keysDir;
VerifyResult vr = Verifier::verify( dsoPath, keysSearch );
if( !quiet )
{
std::printf("%s: %s\n", trustLevelName(vr.trust), dsoPath.c_str());
if( vr.hasManifest )
{
std::printf(" name: %s\n", vr.data.name.c_str());
std::printf(" version: %s\n", vr.data.version.c_str());
std::printf(" author: %s\n", vr.data.author.c_str());
std::printf(" key: %s\n", vr.data.publicKeyId.c_str());
std::printf(" signed: %s\n", vr.data.timestamp.c_str());
}
if( !vr.detail.empty() )
std::printf(" detail: %s\n", vr.detail.c_str());
}
switch( vr.trust )
{
case TrustLevel::TRUSTED: return 0;
case TrustLevel::UNKNOWN: return 1;
case TrustLevel::UNSIGNED: return 2;
case TrustLevel::REJECTED: return 3;
}
return 4;
}