Skip to content
Snippets Groups Projects
Commit ac0e66d9 authored by Christian Kandeler's avatar Christian Kandeler
Browse files

SSH: Support creation of ECDSA keys.


Change-Id: Id5b5ed289a3fd86bd8b84e6429c18f417ca793a7
Reviewed-by: default avatarLeena Miettinen <riitta-leena.miettinen@theqtcompany.com>
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@theqtcompany.com>
parent 8f5618c3
No related branches found
No related tags found
No related merge requests found
......@@ -256,19 +256,23 @@ bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &p
try {
Pipe pipe;
pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
Private_Key * const key = PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever());
if (DSA_PrivateKey * const dsaKey = dynamic_cast<DSA_PrivateKey *>(key)) {
m_authKey.reset(PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever()));
if (auto * const dsaKey = dynamic_cast<DSA_PrivateKey *>(m_authKey.data())) {
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
m_authKey.reset(dsaKey);
pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
<< dsaKey->group_g() << dsaKey->get_y();
allKeyParams << pubKeyParams << dsaKey->get_x();
} else if (RSA_PrivateKey * const rsaKey = dynamic_cast<RSA_PrivateKey *>(key)) {
} else if (auto * const rsaKey = dynamic_cast<RSA_PrivateKey *>(m_authKey.data())) {
m_authKeyAlgoName = SshCapabilities::PubKeyRsa;
m_authKey.reset(rsaKey);
pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
<< rsaKey->get_d();
} else if (auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data())) {
const BigInt value = ecdsaKey->private_value();
m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(value.bytes());
pubKeyParams << ecdsaKey->public_point().get_affine_x()
<< ecdsaKey->public_point().get_affine_y();
allKeyParams << pubKeyParams << value;
} else {
qWarning("%s: Unexpected code flow, expected success or exception.", Q_FUNC_INFO);
return false;
......
......@@ -64,6 +64,7 @@ SshKeyCreationDialog::SshKeyCreationDialog(QWidget *parent)
this, &SshKeyCreationDialog::handleBrowseButtonClicked);
connect(m_ui->generateButton, &QPushButton::clicked,
this, &SshKeyCreationDialog::generateKeys);
keyTypeChanged();
}
SshKeyCreationDialog::~SshKeyCreationDialog()
......@@ -74,8 +75,16 @@ SshKeyCreationDialog::~SshKeyCreationDialog()
void SshKeyCreationDialog::keyTypeChanged()
{
m_ui->comboBox->setCurrentIndex(0);
m_ui->comboBox->setEnabled(m_ui->rsa->isChecked());
m_ui->comboBox->clear();
QStringList keySizes;
if (m_ui->rsa->isChecked())
keySizes << QLatin1String("1024") << QLatin1String("2048") << QLatin1String("4096");
else if (m_ui->ecdsa->isChecked())
keySizes << QLatin1String("256") << QLatin1String("384") << QLatin1String("521");
m_ui->comboBox->addItems(keySizes);
if (!keySizes.isEmpty())
m_ui->comboBox->setCurrentIndex(0);
m_ui->comboBox->setEnabled(!keySizes.isEmpty());
}
void SshKeyCreationDialog::generateKeys()
......@@ -84,8 +93,8 @@ void SshKeyCreationDialog::generateKeys()
return;
const SshKeyGenerator::KeyType keyType = m_ui->rsa->isChecked()
? SshKeyGenerator::Rsa
: SshKeyGenerator::Dsa;
? SshKeyGenerator::Rsa : m_ui->dsa->isChecked()
? SshKeyGenerator::Dsa : SshKeyGenerator::Ecdsa;
if (!m_keyGenerator)
m_keyGenerator = new SshKeyGenerator;
......
......@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>295</width>
<height>223</height>
<width>380</width>
<height>231</height>
</rect>
</property>
<property name="sizePolicy">
......@@ -67,6 +67,13 @@
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="ecdsa">
<property name="text">
<string>ECDSA</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
......@@ -102,21 +109,6 @@
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QComboBox" name="comboBox">
<item>
<property name="text">
<string notr="true">1024</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">2048</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">4096</string>
</property>
</item>
</widget>
</item>
<item>
......
......@@ -32,6 +32,7 @@
#include "sshbotanconversions_p.h"
#include "sshcapabilities_p.h"
#include "ssh_global.h"
#include "sshinit_p.h"
#include "sshpacket_p.h"
......@@ -61,10 +62,19 @@ bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int ke
try {
AutoSeeded_RNG rng;
KeyPtr key;
if (m_type == Rsa)
switch (m_type) {
case Rsa:
key = KeyPtr(new RSA_PrivateKey(rng, keySize));
else
break;
case Dsa:
key = KeyPtr(new DSA_PrivateKey(rng, DL_Group(rng, DL_Group::DSA_Kosherizer, keySize)));
break;
case Ecdsa: {
const QByteArray algo = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(keySize / 8);
key = KeyPtr(new ECDSA_PrivateKey(rng, EC_Group(SshCapabilities::oid(algo))));
break;
}
}
switch (format) {
case Pkcs8:
generatePkcs8KeyStrings(key, rng);
......@@ -125,19 +135,35 @@ void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key)
{
QList<BigInt> params;
QByteArray keyId;
if (m_type == Rsa) {
QByteArray q;
switch (m_type) {
case Rsa: {
const QSharedPointer<RSA_PrivateKey> rsaKey = key.dynamicCast<RSA_PrivateKey>();
params << rsaKey->get_e() << rsaKey->get_n();
keyId = SshCapabilities::PubKeyRsa;
} else {
break;
}
case Dsa: {
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y();
keyId = SshCapabilities::PubKeyDss;
break;
}
case Ecdsa: {
const auto ecdsaKey = key.dynamicCast<ECDSA_PrivateKey>();
q = convertByteArray(EC2OSP(ecdsaKey->public_point(), PointGFp::UNCOMPRESSED));
keyId = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth(ecdsaKey->private_value().bytes());
break;
}
}
QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId);
foreach (const BigInt &b, params)
publicKeyBlob += AbstractSshPacket::encodeMpInt(b);
if (!q.isEmpty()) {
publicKeyBlob += AbstractSshPacket::encodeString(keyId.mid(11)); // Without "ecdsa-sha2-" prefix.
publicKeyBlob += AbstractSshPacket::encodeString(q);
}
publicKeyBlob = publicKeyBlob.toBase64();
const QByteArray id = "QtCreator/"
+ QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8();
......@@ -147,9 +173,9 @@ void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key)
void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key)
{
QList<BigInt> params;
QByteArray keyId;
const char *label;
if (m_type == Rsa) {
switch (m_type) {
case Rsa: {
const QSharedPointer<RSA_PrivateKey> rsaKey
= key.dynamicCast<RSA_PrivateKey>();
params << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() << rsaKey->get_p()
......@@ -158,14 +184,19 @@ void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key)
const BigInt dmq1 = rsaKey->get_d() % (rsaKey->get_q() - 1);
const BigInt iqmp = inverse_mod(rsaKey->get_q(), rsaKey->get_p());
params << dmp1 << dmq1 << iqmp;
keyId = SshCapabilities::PubKeyRsa;
label = "RSA PRIVATE KEY";
} else {
break;
}
case Dsa: {
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y()
<< dsaKey->get_x();
keyId = SshCapabilities::PubKeyDss;
label = "DSA PRIVATE KEY";
break;
}
case Ecdsa:
params << key.dynamicCast<ECDSA_PrivateKey>()->private_value();
label = "EC PRIVATE KEY";
}
DER_Encoder encoder;
......
......@@ -47,7 +47,7 @@ class QSSH_EXPORT SshKeyGenerator
{
Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator)
public:
enum KeyType { Rsa, Dsa };
enum KeyType { Rsa, Dsa, Ecdsa };
enum PrivateKeyFormat { Pkcs8, OpenSsl, Mixed };
enum EncryptionMode { DoOfferEncryption, DoNotOfferEncryption }; // Only relevant for Pkcs8 format.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment