mirror of
https://github.com/QuasarApp/qca.git
synced 2025-04-28 20:44:31 +00:00
994 lines
22 KiB
C++
994 lines
22 KiB
C++
|
#include <QtCore>
|
||
|
#include <QtCrypto>
|
||
|
|
||
|
Q_IMPORT_PLUGIN(opensslPlugin);
|
||
|
|
||
|
class AnimatedKeyGen : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
static QCA::PrivateKey makeKey(QCA::PKey::Type type, int bits, QCA::DLGroupSet set)
|
||
|
{
|
||
|
AnimatedKeyGen kg;
|
||
|
kg.type = type;
|
||
|
kg.bits = bits;
|
||
|
kg.set = set;
|
||
|
QEventLoop eventLoop;
|
||
|
kg.eventLoop = &eventLoop;
|
||
|
QTimer::singleShot(0, &kg, SLOT(start()));
|
||
|
eventLoop.exec();
|
||
|
QCA::PrivateKey key = kg.key;
|
||
|
return key;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
QCA::PKey::Type type;
|
||
|
int bits;
|
||
|
QCA::DLGroupSet set;
|
||
|
QEventLoop *eventLoop;
|
||
|
QCA::KeyGenerator gen;
|
||
|
QCA::DLGroup group;
|
||
|
QCA::PrivateKey key;
|
||
|
QTimer t;
|
||
|
int x;
|
||
|
|
||
|
AnimatedKeyGen()
|
||
|
{
|
||
|
gen.setBlocking(false);
|
||
|
connect(&gen, SIGNAL(finished()), SLOT(gen_finished()));
|
||
|
connect(&t, SIGNAL(timeout()), SLOT(t_timeout()));
|
||
|
}
|
||
|
|
||
|
private slots:
|
||
|
void start()
|
||
|
{
|
||
|
printf("Generating Key ... ");
|
||
|
fflush(stdout);
|
||
|
x = 0;
|
||
|
t.start(125);
|
||
|
|
||
|
if(type == QCA::PKey::RSA)
|
||
|
gen.createRSA(bits);
|
||
|
else
|
||
|
gen.createDLGroup(set);
|
||
|
}
|
||
|
|
||
|
void gen_finished()
|
||
|
{
|
||
|
if(type == QCA::PKey::DSA || type == QCA::PKey::DH)
|
||
|
{
|
||
|
if(group.isNull())
|
||
|
{
|
||
|
group = gen.dlGroup();
|
||
|
|
||
|
if(type == QCA::PKey::DSA)
|
||
|
gen.createDSA(group);
|
||
|
else
|
||
|
gen.createDH(group);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
key = gen.key();
|
||
|
|
||
|
printf("\b");
|
||
|
if(!key.isNull())
|
||
|
printf("Done\n");
|
||
|
else
|
||
|
printf("Error\n");
|
||
|
|
||
|
eventLoop->exit();
|
||
|
}
|
||
|
|
||
|
void t_timeout()
|
||
|
{
|
||
|
if(x == 0)
|
||
|
printf("\b/");
|
||
|
else if(x == 1)
|
||
|
printf("\b-");
|
||
|
else if(x == 2)
|
||
|
printf("\b\\");
|
||
|
else if(x == 3)
|
||
|
printf("\b|");
|
||
|
fflush(stdout);
|
||
|
|
||
|
++x;
|
||
|
x %= 4;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#include "main.moc"
|
||
|
|
||
|
static bool write_dhprivatekey_file(const QCA::PrivateKey &priv, const QString &fileName)
|
||
|
{
|
||
|
QCA::DHPrivateKey key = priv.toDH();
|
||
|
QFile f(fileName);
|
||
|
if(!f.open(QFile::WriteOnly | QFile::Truncate))
|
||
|
return false;
|
||
|
QTextStream ts(&f);
|
||
|
ts << "P:" << QCA::arrayToHex(key.domain().p().toArray()).toLatin1() << endl;
|
||
|
ts << "G:" << QCA::arrayToHex(key.domain().g().toArray()).toLatin1() << endl;
|
||
|
ts << "Y:" << QCA::arrayToHex(key.y().toArray()).toLatin1() << endl;
|
||
|
ts << "X:" << QCA::arrayToHex(key.x().toArray()).toLatin1() << endl;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool write_dhpublickey_file(const QCA::PublicKey &pub, const QString &fileName)
|
||
|
{
|
||
|
QCA::DHPublicKey key = pub.toDH();
|
||
|
QFile f(fileName);
|
||
|
if(!f.open(QFile::WriteOnly | QFile::Truncate))
|
||
|
return false;
|
||
|
QTextStream ts(&f);
|
||
|
ts << "P:" << QCA::arrayToHex(key.domain().p().toArray()).toLatin1() << endl;
|
||
|
ts << "G:" << QCA::arrayToHex(key.domain().g().toArray()).toLatin1() << endl;
|
||
|
ts << "Y:" << QCA::arrayToHex(key.y().toArray()).toLatin1() << endl;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static QMap<QString, QBigInteger> read_map_file(const QString &fileName)
|
||
|
{
|
||
|
QMap<QString, QBigInteger> map;
|
||
|
|
||
|
QFile f(fileName);
|
||
|
if(!f.open(QFile::ReadOnly))
|
||
|
return map;
|
||
|
QTextStream ts(&f);
|
||
|
while(!ts.atEnd())
|
||
|
{
|
||
|
QString line = ts.readLine();
|
||
|
QStringList pair = line.split(':');
|
||
|
QSecureArray bin = QCA::hexToArray(pair[1]);
|
||
|
map[pair[0]] = QBigInteger(bin);
|
||
|
}
|
||
|
return map;
|
||
|
}
|
||
|
|
||
|
static QCA::PrivateKey read_dhprivatekey_file(const QString &fileName)
|
||
|
{
|
||
|
QCA::PrivateKey key;
|
||
|
QMap<QString, QBigInteger> map;
|
||
|
map = read_map_file(fileName);
|
||
|
if(map.isEmpty())
|
||
|
return key;
|
||
|
return QCA::DHPrivateKey(QCA::DLGroup(map["P"], map["G"]), map["Y"], map["X"]);
|
||
|
}
|
||
|
|
||
|
static QCA::PublicKey read_dhpublickey_file(const QString &fileName)
|
||
|
{
|
||
|
QCA::PublicKey key;
|
||
|
QMap<QString, QBigInteger> map;
|
||
|
map = read_map_file(fileName);
|
||
|
if(map.isEmpty())
|
||
|
return key;
|
||
|
return QCA::DHPublicKey(QCA::DLGroup(map["P"], map["G"]), map["Y"]);
|
||
|
}
|
||
|
|
||
|
static QString prompt_for(const QString &prompt)
|
||
|
{
|
||
|
printf("%s: ", prompt.toLatin1().data());
|
||
|
fflush(stdout);
|
||
|
QByteArray result(256, 0);
|
||
|
fgets((char *)result.data(), result.size(), stdin);
|
||
|
return QString::fromLatin1(result).trimmed();
|
||
|
}
|
||
|
|
||
|
static void try_print_info(const QString &name, const QString &value)
|
||
|
{
|
||
|
if(!value.isEmpty())
|
||
|
printf(" %s: %s\n", name.toLatin1().data(), value.toLatin1().data());
|
||
|
}
|
||
|
|
||
|
static void print_info(const QString &title, const QCA::CertificateInfo &info)
|
||
|
{
|
||
|
printf("%s\n", title.toLatin1().data());
|
||
|
try_print_info("Name", info.value(QCA::CommonName));
|
||
|
try_print_info("Email", info.value(QCA::Email));
|
||
|
try_print_info("Organization", info.value(QCA::Organization));
|
||
|
try_print_info("Organizational Unit", info.value(QCA::OrganizationalUnit));
|
||
|
try_print_info("Locality", info.value(QCA::Locality));
|
||
|
try_print_info("State", info.value(QCA::State));
|
||
|
try_print_info("Country", info.value(QCA::Country));
|
||
|
try_print_info("URI", info.value(QCA::URI));
|
||
|
try_print_info("DNS", info.value(QCA::DNS));
|
||
|
try_print_info("IP Address", info.value(QCA::IPAddress));
|
||
|
try_print_info("JID", info.value(QCA::XMPP));
|
||
|
}
|
||
|
|
||
|
static QString constraint_to_string(QCA::ConstraintType t)
|
||
|
{
|
||
|
QString str;
|
||
|
switch(t)
|
||
|
{
|
||
|
case QCA::DigitalSignature: str = "Digital Signature"; break;
|
||
|
case QCA::NonRepudiation: str = "Non-Repudiation"; break;
|
||
|
case QCA::KeyEncipherment: str = "Key Encipherment"; break;
|
||
|
case QCA::DataEncipherment: str = "Data Encipherment"; break;
|
||
|
case QCA::KeyAgreement: str = "Key Agreement"; break;
|
||
|
case QCA::KeyCertificateSign: str = "Certificate Sign"; break;
|
||
|
case QCA::CRLSign: str = "CRL Sign"; break;
|
||
|
case QCA::EncipherOnly: str = "Encipher Only"; break;
|
||
|
case QCA::DecipherOnly: str = "Decipher Only"; break;
|
||
|
case QCA::ServerAuth: str = "TLS Server Authentication"; break;
|
||
|
case QCA::ClientAuth: str = "TLS Client Authentication"; break;
|
||
|
case QCA::CodeSigning: str = "Code Signing"; break;
|
||
|
case QCA::EmailProtection: str = "Email Protection"; break;
|
||
|
case QCA::IPSecEndSystem: str = "IPSec End System"; break;
|
||
|
case QCA::IPSecTunnel: str = "IPSec Tunnel"; break;
|
||
|
case QCA::IPSecUser: str = "IPSec User"; break;
|
||
|
case QCA::TimeStamping: str = "Time Stamping"; break;
|
||
|
case QCA::OCSPSigning: str = "OCSP Signing"; break;
|
||
|
}
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
static QString validityToString(QCA::Validity v)
|
||
|
{
|
||
|
QString s;
|
||
|
switch(v)
|
||
|
{
|
||
|
case QCA::ValidityGood:
|
||
|
s = "Validated";
|
||
|
break;
|
||
|
case QCA::ErrorRejected:
|
||
|
s = "Root CA is marked to reject the specified purpose";
|
||
|
break;
|
||
|
case QCA::ErrorUntrusted:
|
||
|
s = "Certificate not trusted for the required purpose";
|
||
|
break;
|
||
|
case QCA::ErrorSignatureFailed:
|
||
|
s = "Invalid signature";
|
||
|
break;
|
||
|
case QCA::ErrorInvalidCA:
|
||
|
s = "Invalid CA certificate";
|
||
|
break;
|
||
|
case QCA::ErrorInvalidPurpose:
|
||
|
s = "Invalid certificate purpose";
|
||
|
break;
|
||
|
case QCA::ErrorSelfSigned:
|
||
|
s = "Certificate is self-signed";
|
||
|
break;
|
||
|
case QCA::ErrorRevoked:
|
||
|
s = "Certificate has been revoked";
|
||
|
break;
|
||
|
case QCA::ErrorPathLengthExceeded:
|
||
|
s = "Maximum certificate chain length exceeded";
|
||
|
break;
|
||
|
case QCA::ErrorExpired:
|
||
|
s = "Certificate has expired";
|
||
|
break;
|
||
|
case QCA::ErrorExpiredCA:
|
||
|
s = "CA has expired";
|
||
|
break;
|
||
|
case QCA::ErrorValidityUnknown:
|
||
|
default:
|
||
|
s = "General certificate validation error";
|
||
|
break;
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
|
static void usage()
|
||
|
{
|
||
|
printf("qcatool: simple qca testing tool\n");
|
||
|
printf("usage: qcatool [--command] (options)\n");
|
||
|
printf("commands:\n");
|
||
|
printf(" --help\n");
|
||
|
printf("\n");
|
||
|
printf(" --genrsa [bits] (passphrase)\n");
|
||
|
printf(" --gendsa [512|768|1024] (passphrase)\n");
|
||
|
printf(" --gendh [1024|2048|4096]\n");
|
||
|
printf("\n");
|
||
|
printf(" --encrypt [pub.pem] [messagefile]\n");
|
||
|
printf(" --decrypt [priv.pem] [encryptedfile] (passphrase)\n");
|
||
|
printf(" --sign [priv.pem] [messagefile] (passphrase)\n");
|
||
|
printf(" --verify [pub.pem] [messagefile] [sigfile]\n");
|
||
|
printf(" --derivekey [priv.txt] [peerpub.txt]\n");
|
||
|
printf("\n");
|
||
|
printf(" --makeselfcert [priv.pem] [ca|user] (passphrase)\n");
|
||
|
printf(" --makereq [priv.pem] (passphrase)\n");
|
||
|
printf(" --showcert [cert.pem]\n");
|
||
|
printf(" --showreq [certreq.pem]\n");
|
||
|
printf(" --validate [cert.pem] (nonrootstore.pem)\n");
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
QCA::Initializer qcaInit;
|
||
|
|
||
|
QCoreApplication app(argc, argv);
|
||
|
|
||
|
QCA::scanForPlugins();
|
||
|
|
||
|
if(!QCA::isSupported("pkey") || !QCA::PKey::supportedTypes().contains(QCA::PKey::RSA) || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA))
|
||
|
{
|
||
|
printf("Error: no RSA support\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!QCA::PKey::supportedTypes().contains(QCA::PKey::DSA) || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::DSA))
|
||
|
{
|
||
|
printf("Error: no DSA support\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!QCA::PKey::supportedTypes().contains(QCA::PKey::DH))
|
||
|
{
|
||
|
printf("Error: no DH support\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QStringList args;
|
||
|
for(int n = 1; n < argc; ++n)
|
||
|
args.append(QString(argv[n]));
|
||
|
|
||
|
if(args.count() < 1)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(args[0] == "--help")
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool genrsa = false;
|
||
|
bool gendsa = false;
|
||
|
bool gendh = false;
|
||
|
|
||
|
if(args[0] == "--genrsa")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
genrsa = true;
|
||
|
}
|
||
|
if(args[0] == "--gendsa")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
gendsa = true;
|
||
|
}
|
||
|
else if(args[0] == "--gendh")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
gendh = true;
|
||
|
}
|
||
|
|
||
|
if(genrsa || gendsa || gendh)
|
||
|
{
|
||
|
QCA::PrivateKey priv;
|
||
|
QString pubname, privname;
|
||
|
|
||
|
if(genrsa)
|
||
|
{
|
||
|
int bits = args[1].toInt();
|
||
|
|
||
|
// note: last arg here is bogus
|
||
|
priv = AnimatedKeyGen::makeKey(QCA::PKey::RSA, bits, QCA::DSA_512);
|
||
|
pubname = "rsapub.pem";
|
||
|
privname = "rsapriv.pem";
|
||
|
}
|
||
|
else if(gendsa)
|
||
|
{
|
||
|
QCA::DLGroupSet set;
|
||
|
if(args[1] == "512")
|
||
|
set = QCA::DSA_512;
|
||
|
else if(args[1] == "768")
|
||
|
set = QCA::DSA_768;
|
||
|
else if(args[1] == "1024")
|
||
|
set = QCA::DSA_1024;
|
||
|
else
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
priv = AnimatedKeyGen::makeKey(QCA::PKey::DSA, 0, set);
|
||
|
pubname = "dsapub.pem";
|
||
|
privname = "dsapriv.pem";
|
||
|
}
|
||
|
else if(gendh)
|
||
|
{
|
||
|
QCA::DLGroupSet set;
|
||
|
if(args[1] == "1024")
|
||
|
set = QCA::IETF_1024;
|
||
|
else if(args[1] == "2048")
|
||
|
set = QCA::IETF_2048;
|
||
|
else if(args[1] == "4096")
|
||
|
set = QCA::IETF_4096;
|
||
|
else
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
priv = AnimatedKeyGen::makeKey(QCA::PKey::DH, 0, set);
|
||
|
pubname = "dhpub.txt";
|
||
|
privname = "dhpriv.txt";
|
||
|
}
|
||
|
|
||
|
if(priv.isNull())
|
||
|
{
|
||
|
printf("Error: unable to generate key\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::PublicKey pub = priv.toPublicKey();
|
||
|
|
||
|
if(genrsa || gendsa)
|
||
|
{
|
||
|
QSecureArray passphrase;
|
||
|
if(args.count() >= 3)
|
||
|
passphrase = args[2].toLatin1();
|
||
|
|
||
|
if(pub.toPEMFile(pubname))
|
||
|
printf("Public key saved to %s\n", pubname.toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error writing %s\n", pubname.toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool ok;
|
||
|
if(!passphrase.isEmpty())
|
||
|
ok = priv.toPEMFile(privname, passphrase);
|
||
|
else
|
||
|
ok = priv.toPEMFile(privname);
|
||
|
if(ok)
|
||
|
printf("Private key saved to %s\n", privname.toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error writing %s\n", privname.toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(write_dhpublickey_file(pub, pubname))
|
||
|
printf("Public key saved to %s\n", pubname.toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error writing %s\n", pubname.toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(write_dhprivatekey_file(priv, privname))
|
||
|
printf("Private key saved to %s\n", privname.toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error writing %s\n", privname.toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if(args[0] == "--encrypt")
|
||
|
{
|
||
|
if(args.count() < 3)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::PublicKey key(args[1]);
|
||
|
if(key.isNull())
|
||
|
{
|
||
|
printf("Error reading key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!key.canEncrypt())
|
||
|
{
|
||
|
printf("Error: this kind of key cannot encrypt\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::EncryptionAlgorithm alg = QCA::EME_PKCS1_OAEP;
|
||
|
int max = key.maximumEncryptSize(alg);
|
||
|
|
||
|
QByteArray buf;
|
||
|
{
|
||
|
QFile infile(args[2]);
|
||
|
if(!infile.open(QFile::ReadOnly))
|
||
|
{
|
||
|
printf("Error opening message file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(infile.size() > max)
|
||
|
fprintf(stderr, "Warning: input size is greater than key maximum, result will be truncated\n");
|
||
|
|
||
|
buf = infile.read(max);
|
||
|
}
|
||
|
|
||
|
QFile outfile("rsaenc.txt");
|
||
|
if(!outfile.open(QFile::WriteOnly | QFile::Truncate))
|
||
|
{
|
||
|
printf("Error opening output file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QSecureArray result = key.encrypt(buf, alg);
|
||
|
|
||
|
QString str = QCA::Base64().arrayToString(result);
|
||
|
QTextStream ts(&outfile);
|
||
|
ts << str << endl;
|
||
|
|
||
|
printf("Wrote %s\n", outfile.fileName().toLatin1().data());
|
||
|
}
|
||
|
else if(args[0] == "--decrypt")
|
||
|
{
|
||
|
if(args.count() < 3)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QSecureArray passphrase;
|
||
|
if(args.count() >= 4)
|
||
|
passphrase = args[3].toLatin1();
|
||
|
|
||
|
QCA::PrivateKey key;
|
||
|
if(!passphrase.isEmpty())
|
||
|
key = QCA::PrivateKey(args[1], passphrase);
|
||
|
else
|
||
|
key = QCA::PrivateKey(args[1]);
|
||
|
if(key.isNull())
|
||
|
{
|
||
|
printf("Error reading key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!key.canDecrypt())
|
||
|
{
|
||
|
printf("Error: this kind of key cannot create decrypt\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::EncryptionAlgorithm alg = QCA::EME_PKCS1_OAEP;
|
||
|
|
||
|
QSecureArray buf;
|
||
|
{
|
||
|
QFile infile(args[2]);
|
||
|
if(!infile.open(QFile::ReadOnly))
|
||
|
{
|
||
|
printf("Error opening input file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
QTextStream ts(&infile);
|
||
|
QString str = ts.readLine();
|
||
|
buf = QCA::Base64().stringToArray(str);
|
||
|
}
|
||
|
|
||
|
QSecureArray result;
|
||
|
if(!key.decrypt(buf, &result, alg))
|
||
|
{
|
||
|
printf("Error decrypting\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
printf("%s\n", result.data());
|
||
|
}
|
||
|
else if(args[0] == "--sign")
|
||
|
{
|
||
|
if(args.count() < 3)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QSecureArray passphrase;
|
||
|
if(args.count() >= 4)
|
||
|
passphrase = args[3].toLatin1();
|
||
|
|
||
|
QCA::PrivateKey key;
|
||
|
if(!passphrase.isEmpty())
|
||
|
key = QCA::PrivateKey(args[1], passphrase);
|
||
|
else
|
||
|
key = QCA::PrivateKey(args[1]);
|
||
|
if(key.isNull())
|
||
|
{
|
||
|
printf("Error reading key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!key.canSign())
|
||
|
{
|
||
|
printf("Error: this kind of key cannot create signatures\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QFile infile(args[2]);
|
||
|
QFile outfile(infile.fileName() + ".sig");
|
||
|
if(!infile.open(QFile::ReadOnly) || !outfile.open(QFile::WriteOnly | QFile::Truncate))
|
||
|
{
|
||
|
printf("Error opening message or signature files\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(key.isRSA())
|
||
|
key.startSign(QCA::EMSA3_MD5);
|
||
|
else
|
||
|
key.startSign(QCA::EMSA1_SHA1);
|
||
|
while(!infile.atEnd())
|
||
|
key.update(infile.read(16384));
|
||
|
QSecureArray sig = key.signature();
|
||
|
|
||
|
QString str = QCA::Base64().arrayToString(sig);
|
||
|
QTextStream ts(&outfile);
|
||
|
ts << str << endl;
|
||
|
|
||
|
printf("Wrote %s\n", outfile.fileName().toLatin1().data());
|
||
|
}
|
||
|
else if(args[0] == "--verify")
|
||
|
{
|
||
|
if(args.count() < 4)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::PublicKey key(args[1]);
|
||
|
if(key.isNull())
|
||
|
{
|
||
|
printf("Error reading key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!key.canVerify())
|
||
|
{
|
||
|
printf("Error: this kind of key cannot verify signatures\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QSecureArray sig;
|
||
|
{
|
||
|
QFile sigfile(args[3]);
|
||
|
if(!sigfile.open(QFile::ReadOnly))
|
||
|
{
|
||
|
printf("Error opening signature file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
QTextStream ts(&sigfile);
|
||
|
QString str = ts.readLine();
|
||
|
sig = QCA::Base64().stringToArray(str);
|
||
|
}
|
||
|
|
||
|
QFile infile(args[2]);
|
||
|
if(!infile.open(QFile::ReadOnly))
|
||
|
{
|
||
|
printf("Error opening message file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(key.isRSA())
|
||
|
key.startVerify(QCA::EMSA3_MD5);
|
||
|
else
|
||
|
key.startVerify(QCA::EMSA1_SHA1);
|
||
|
while(!infile.atEnd())
|
||
|
key.update(infile.read(16384));
|
||
|
if(key.validSignature(sig))
|
||
|
printf("Signature verified\n");
|
||
|
else
|
||
|
{
|
||
|
printf("Signature did NOT verify\n");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if(args[0] == "--derivekey")
|
||
|
{
|
||
|
if(args.count() < 3)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::PrivateKey priv = read_dhprivatekey_file(args[1]);
|
||
|
if(priv.isNull())
|
||
|
{
|
||
|
printf("Error reading private key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!priv.canKeyAgree())
|
||
|
{
|
||
|
printf("Error: the private key cannot be used to derive shared keys\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::PublicKey pub = read_dhpublickey_file(args[2]);
|
||
|
if(pub.isNull())
|
||
|
{
|
||
|
printf("Error reading public key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!pub.canKeyAgree())
|
||
|
{
|
||
|
printf("Error: the public key cannot be used to derive shared keys\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::SymmetricKey key = priv.deriveKey(pub);
|
||
|
if(!key.isEmpty())
|
||
|
printf("%s\n", QCA::Base64().arrayToString(key).toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error deriving key\n");
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if(args[0] == "--makeselfcert")
|
||
|
{
|
||
|
if(args.count() < 3)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QSecureArray passphrase;
|
||
|
if(args.count() >= 4)
|
||
|
passphrase = args[3].toLatin1();
|
||
|
|
||
|
QCA::PrivateKey key;
|
||
|
if(!passphrase.isEmpty())
|
||
|
key = QCA::PrivateKey(args[1], passphrase);
|
||
|
else
|
||
|
key = QCA::PrivateKey(args[1]);
|
||
|
if(key.isNull())
|
||
|
{
|
||
|
printf("Error reading key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
bool do_ca;
|
||
|
if(args[2] == "ca")
|
||
|
do_ca = true;
|
||
|
else if(args[2] == "user")
|
||
|
do_ca = false;
|
||
|
else
|
||
|
{
|
||
|
printf("Must specify 'ca' or 'user' as type\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::CertificateOptions opts;
|
||
|
//opts.setSerialNumber(QBigInteger("1000000000000"));
|
||
|
QCA::CertificateInfo info;
|
||
|
info[QCA::CommonName] = prompt_for("Common Name");
|
||
|
info[QCA::Country] = prompt_for("Country Code (2 letters)");
|
||
|
info[QCA::Organization] = prompt_for("Organization");
|
||
|
info[QCA::Email] = prompt_for("Email");
|
||
|
|
||
|
//info[QCA::URI] = "http://psi.affinix.com/";
|
||
|
//info[QCA::DNS] = "psi.affinix.com";
|
||
|
//info[QCA::IPAddress] = "192.168.0.1";
|
||
|
//info[QCA::XMPP] = "justin@andbit.net";
|
||
|
|
||
|
opts.setInfo(info);
|
||
|
if(do_ca)
|
||
|
opts.setAsCA();
|
||
|
|
||
|
//QCA::Constraints constraints;
|
||
|
//constraints += QCA::ServerAuth;
|
||
|
//constraints += QCA::CodeSigning;
|
||
|
//opts.setConstraints(constraints);
|
||
|
|
||
|
//QStringList policies;
|
||
|
//policies += "1.2.3.4";
|
||
|
//policies += "1.6.7.8";
|
||
|
//opts.setPolicies(policies);
|
||
|
|
||
|
QDateTime t = QDateTime::currentDateTime().toUTC();
|
||
|
opts.setValidityPeriod(t, t.addMonths(1));
|
||
|
|
||
|
QCA::Certificate cert(opts, key);
|
||
|
|
||
|
QString certname = "cert.pem";
|
||
|
if(cert.toPEMFile(certname))
|
||
|
printf("Certificate saved to %s\n", certname.toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error writing %s\n", certname.toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if(args[0] == "--makereq")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QSecureArray passphrase;
|
||
|
if(args.count() >= 3)
|
||
|
passphrase = args[2].toLatin1();
|
||
|
|
||
|
QCA::PrivateKey key;
|
||
|
if(!passphrase.isEmpty())
|
||
|
key = QCA::PrivateKey(args[1], passphrase);
|
||
|
else
|
||
|
key = QCA::PrivateKey(args[1]);
|
||
|
if(key.isNull())
|
||
|
{
|
||
|
printf("Error reading key file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::CertificateOptions opts;
|
||
|
QCA::CertificateInfo info;
|
||
|
info[QCA::CommonName] = prompt_for("Common Name");
|
||
|
info[QCA::Country] = prompt_for("Country Code (2 letters)");
|
||
|
info[QCA::Organization] = prompt_for("Organization");
|
||
|
info[QCA::Email] = prompt_for("Email");
|
||
|
|
||
|
opts.setInfo(info);
|
||
|
|
||
|
//if(do_ca)
|
||
|
// opts.setAsCA();
|
||
|
|
||
|
//QCA::Constraints constraints;
|
||
|
//constraints += QCA::ServerAuth;
|
||
|
//constraints += QCA::CodeSigning;
|
||
|
//opts.setConstraints(constraints);
|
||
|
|
||
|
//QStringList policies;
|
||
|
//policies += "1.2.3.4";
|
||
|
//policies += "1.6.7.8";
|
||
|
//opts.setPolicies(policies);
|
||
|
|
||
|
QDateTime t = QDateTime::currentDateTime().toUTC();
|
||
|
opts.setValidityPeriod(t, t.addMonths(1));
|
||
|
|
||
|
QCA::CertificateRequest req(opts, key);
|
||
|
|
||
|
QString reqname = "certreq.pem";
|
||
|
if(req.toPEMFile(reqname))
|
||
|
printf("Certificate request saved to %s\n", reqname.toLatin1().data());
|
||
|
else
|
||
|
{
|
||
|
printf("Error writing %s\n", reqname.toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else if(args[0] == "--showcert")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::Certificate cert(args[1]);
|
||
|
if(cert.isNull())
|
||
|
{
|
||
|
printf("Error reading cert file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
printf("Serial Number: %s\n", cert.serialNumber().toString().toLatin1().data());
|
||
|
|
||
|
print_info("Subject", cert.subjectInfo());
|
||
|
print_info("Issuer", cert.issuerInfo());
|
||
|
|
||
|
printf("Validity\n");
|
||
|
printf(" Not before: %s\n", cert.notValidBefore().toString().toLatin1().data());
|
||
|
printf(" Not after: %s\n", cert.notValidAfter().toString().toLatin1().data());
|
||
|
|
||
|
printf("Constraints\n");
|
||
|
QCA::Constraints constraints = cert.constraints();
|
||
|
int n;
|
||
|
if(!constraints.isEmpty())
|
||
|
{
|
||
|
for(n = 0; n < constraints.count(); ++n)
|
||
|
printf(" %s\n", constraint_to_string(constraints[n]).toLatin1().data());
|
||
|
}
|
||
|
else
|
||
|
printf(" No constraints\n");
|
||
|
|
||
|
printf("Policies\n");
|
||
|
QStringList policies = cert.policies();
|
||
|
if(!policies.isEmpty())
|
||
|
{
|
||
|
for(n = 0; n < policies.count(); ++n)
|
||
|
printf(" %s\n", policies[n].toLatin1().data());
|
||
|
}
|
||
|
else
|
||
|
printf(" No policies\n");
|
||
|
|
||
|
QCA::PublicKey key = cert.subjectPublicKey();
|
||
|
printf("Public Key:\n%s", key.toPEM().toLatin1().data());
|
||
|
}
|
||
|
else if(args[0] == "--showreq")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::CertificateRequest req(args[1]);
|
||
|
if(req.isNull())
|
||
|
{
|
||
|
printf("Error reading cert request file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
print_info("Subject", req.subjectInfo());
|
||
|
|
||
|
printf("Constraints\n");
|
||
|
QCA::Constraints constraints = req.constraints();
|
||
|
int n;
|
||
|
for(n = 0; n < constraints.count(); ++n)
|
||
|
printf(" %s\n", constraint_to_string(constraints[n]).toLatin1().data());
|
||
|
|
||
|
printf("Policies\n");
|
||
|
QStringList policies = req.policies();
|
||
|
for(n = 0; n < policies.count(); ++n)
|
||
|
printf(" %s\n", policies[n].toLatin1().data());
|
||
|
|
||
|
QCA::PublicKey key = req.subjectPublicKey();
|
||
|
printf("Public Key:\n%s", key.toPEM().toLatin1().data());
|
||
|
}
|
||
|
else if(args[0] == "--validate")
|
||
|
{
|
||
|
if(args.count() < 2)
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
QCA::Certificate target(args[1]);
|
||
|
if(target.isNull())
|
||
|
{
|
||
|
printf("Error reading cert file\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if(!QCA::haveSystemStore())
|
||
|
{
|
||
|
printf("Error: no system store\n");
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
// get roots
|
||
|
QCA::Store store = QCA::systemStore();
|
||
|
|
||
|
// get nonroots
|
||
|
if(args.count() >= 3)
|
||
|
store += QCA::Store::fromFlatTextFile(args[2]);
|
||
|
|
||
|
QCA::Validity v = store.validate(target);
|
||
|
if(v == QCA::ValidityGood)
|
||
|
printf("Certificate is valid\n");
|
||
|
else
|
||
|
{
|
||
|
printf("Certificate is NOT valid: %s\n", validityToString(v).toLatin1().data());
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
usage();
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|