forked from qt-creator/qt-creator
SSH: Support creation of ECDSA keys.
Change-Id: Id5b5ed289a3fd86bd8b84e6429c18f417ca793a7 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@theqtcompany.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
@@ -256,19 +256,23 @@ bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &p
|
|||||||
try {
|
try {
|
||||||
Pipe pipe;
|
Pipe pipe;
|
||||||
pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
|
pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size());
|
||||||
Private_Key * const key = PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever());
|
m_authKey.reset(PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever()));
|
||||||
if (DSA_PrivateKey * const dsaKey = dynamic_cast<DSA_PrivateKey *>(key)) {
|
if (auto * const dsaKey = dynamic_cast<DSA_PrivateKey *>(m_authKey.data())) {
|
||||||
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
|
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
|
||||||
m_authKey.reset(dsaKey);
|
|
||||||
pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
|
pubKeyParams << dsaKey->group_p() << dsaKey->group_q()
|
||||||
<< dsaKey->group_g() << dsaKey->get_y();
|
<< dsaKey->group_g() << dsaKey->get_y();
|
||||||
allKeyParams << pubKeyParams << dsaKey->get_x();
|
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_authKeyAlgoName = SshCapabilities::PubKeyRsa;
|
||||||
m_authKey.reset(rsaKey);
|
|
||||||
pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
|
pubKeyParams << rsaKey->get_e() << rsaKey->get_n();
|
||||||
allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
|
allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q()
|
||||||
<< rsaKey->get_d();
|
<< 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 {
|
} else {
|
||||||
qWarning("%s: Unexpected code flow, expected success or exception.", Q_FUNC_INFO);
|
qWarning("%s: Unexpected code flow, expected success or exception.", Q_FUNC_INFO);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ SshKeyCreationDialog::SshKeyCreationDialog(QWidget *parent)
|
|||||||
this, &SshKeyCreationDialog::handleBrowseButtonClicked);
|
this, &SshKeyCreationDialog::handleBrowseButtonClicked);
|
||||||
connect(m_ui->generateButton, &QPushButton::clicked,
|
connect(m_ui->generateButton, &QPushButton::clicked,
|
||||||
this, &SshKeyCreationDialog::generateKeys);
|
this, &SshKeyCreationDialog::generateKeys);
|
||||||
|
keyTypeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
SshKeyCreationDialog::~SshKeyCreationDialog()
|
SshKeyCreationDialog::~SshKeyCreationDialog()
|
||||||
@@ -74,8 +75,16 @@ SshKeyCreationDialog::~SshKeyCreationDialog()
|
|||||||
|
|
||||||
void SshKeyCreationDialog::keyTypeChanged()
|
void SshKeyCreationDialog::keyTypeChanged()
|
||||||
{
|
{
|
||||||
m_ui->comboBox->setCurrentIndex(0);
|
m_ui->comboBox->clear();
|
||||||
m_ui->comboBox->setEnabled(m_ui->rsa->isChecked());
|
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()
|
void SshKeyCreationDialog::generateKeys()
|
||||||
@@ -84,8 +93,8 @@ void SshKeyCreationDialog::generateKeys()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const SshKeyGenerator::KeyType keyType = m_ui->rsa->isChecked()
|
const SshKeyGenerator::KeyType keyType = m_ui->rsa->isChecked()
|
||||||
? SshKeyGenerator::Rsa
|
? SshKeyGenerator::Rsa : m_ui->dsa->isChecked()
|
||||||
: SshKeyGenerator::Dsa;
|
? SshKeyGenerator::Dsa : SshKeyGenerator::Ecdsa;
|
||||||
|
|
||||||
if (!m_keyGenerator)
|
if (!m_keyGenerator)
|
||||||
m_keyGenerator = new SshKeyGenerator;
|
m_keyGenerator = new SshKeyGenerator;
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>295</width>
|
<width>380</width>
|
||||||
<height>223</height>
|
<height>231</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@@ -67,6 +67,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="ecdsa">
|
||||||
|
<property name="text">
|
||||||
|
<string>ECDSA</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_3">
|
<spacer name="horizontalSpacer_3">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@@ -102,21 +109,6 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="comboBox">
|
<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>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "sshbotanconversions_p.h"
|
#include "sshbotanconversions_p.h"
|
||||||
#include "sshcapabilities_p.h"
|
#include "sshcapabilities_p.h"
|
||||||
|
#include "ssh_global.h"
|
||||||
#include "sshinit_p.h"
|
#include "sshinit_p.h"
|
||||||
#include "sshpacket_p.h"
|
#include "sshpacket_p.h"
|
||||||
|
|
||||||
@@ -61,10 +62,19 @@ bool SshKeyGenerator::generateKeys(KeyType type, PrivateKeyFormat format, int ke
|
|||||||
try {
|
try {
|
||||||
AutoSeeded_RNG rng;
|
AutoSeeded_RNG rng;
|
||||||
KeyPtr key;
|
KeyPtr key;
|
||||||
if (m_type == Rsa)
|
switch (m_type) {
|
||||||
|
case Rsa:
|
||||||
key = KeyPtr(new RSA_PrivateKey(rng, keySize));
|
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)));
|
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) {
|
switch (format) {
|
||||||
case Pkcs8:
|
case Pkcs8:
|
||||||
generatePkcs8KeyStrings(key, rng);
|
generatePkcs8KeyStrings(key, rng);
|
||||||
@@ -125,19 +135,35 @@ void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key)
|
|||||||
{
|
{
|
||||||
QList<BigInt> params;
|
QList<BigInt> params;
|
||||||
QByteArray keyId;
|
QByteArray keyId;
|
||||||
if (m_type == Rsa) {
|
QByteArray q;
|
||||||
|
switch (m_type) {
|
||||||
|
case Rsa: {
|
||||||
const QSharedPointer<RSA_PrivateKey> rsaKey = key.dynamicCast<RSA_PrivateKey>();
|
const QSharedPointer<RSA_PrivateKey> rsaKey = key.dynamicCast<RSA_PrivateKey>();
|
||||||
params << rsaKey->get_e() << rsaKey->get_n();
|
params << rsaKey->get_e() << rsaKey->get_n();
|
||||||
keyId = SshCapabilities::PubKeyRsa;
|
keyId = SshCapabilities::PubKeyRsa;
|
||||||
} else {
|
break;
|
||||||
|
}
|
||||||
|
case Dsa: {
|
||||||
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
|
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
|
||||||
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y();
|
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y();
|
||||||
keyId = SshCapabilities::PubKeyDss;
|
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);
|
QByteArray publicKeyBlob = AbstractSshPacket::encodeString(keyId);
|
||||||
foreach (const BigInt &b, params)
|
foreach (const BigInt &b, params)
|
||||||
publicKeyBlob += AbstractSshPacket::encodeMpInt(b);
|
publicKeyBlob += AbstractSshPacket::encodeMpInt(b);
|
||||||
|
if (!q.isEmpty()) {
|
||||||
|
publicKeyBlob += AbstractSshPacket::encodeString(keyId.mid(11)); // Without "ecdsa-sha2-" prefix.
|
||||||
|
publicKeyBlob += AbstractSshPacket::encodeString(q);
|
||||||
|
}
|
||||||
publicKeyBlob = publicKeyBlob.toBase64();
|
publicKeyBlob = publicKeyBlob.toBase64();
|
||||||
const QByteArray id = "QtCreator/"
|
const QByteArray id = "QtCreator/"
|
||||||
+ QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8();
|
+ QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8();
|
||||||
@@ -147,9 +173,9 @@ void SshKeyGenerator::generateOpenSslPublicKeyString(const KeyPtr &key)
|
|||||||
void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key)
|
void SshKeyGenerator::generateOpenSslPrivateKeyString(const KeyPtr &key)
|
||||||
{
|
{
|
||||||
QList<BigInt> params;
|
QList<BigInt> params;
|
||||||
QByteArray keyId;
|
|
||||||
const char *label;
|
const char *label;
|
||||||
if (m_type == Rsa) {
|
switch (m_type) {
|
||||||
|
case Rsa: {
|
||||||
const QSharedPointer<RSA_PrivateKey> rsaKey
|
const QSharedPointer<RSA_PrivateKey> rsaKey
|
||||||
= key.dynamicCast<RSA_PrivateKey>();
|
= key.dynamicCast<RSA_PrivateKey>();
|
||||||
params << rsaKey->get_n() << rsaKey->get_e() << rsaKey->get_d() << rsaKey->get_p()
|
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 dmq1 = rsaKey->get_d() % (rsaKey->get_q() - 1);
|
||||||
const BigInt iqmp = inverse_mod(rsaKey->get_q(), rsaKey->get_p());
|
const BigInt iqmp = inverse_mod(rsaKey->get_q(), rsaKey->get_p());
|
||||||
params << dmp1 << dmq1 << iqmp;
|
params << dmp1 << dmq1 << iqmp;
|
||||||
keyId = SshCapabilities::PubKeyRsa;
|
|
||||||
label = "RSA PRIVATE KEY";
|
label = "RSA PRIVATE KEY";
|
||||||
} else {
|
break;
|
||||||
|
}
|
||||||
|
case Dsa: {
|
||||||
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
|
const QSharedPointer<DSA_PrivateKey> dsaKey = key.dynamicCast<DSA_PrivateKey>();
|
||||||
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y()
|
params << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y()
|
||||||
<< dsaKey->get_x();
|
<< dsaKey->get_x();
|
||||||
keyId = SshCapabilities::PubKeyDss;
|
|
||||||
label = "DSA PRIVATE KEY";
|
label = "DSA PRIVATE KEY";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Ecdsa:
|
||||||
|
params << key.dynamicCast<ECDSA_PrivateKey>()->private_value();
|
||||||
|
label = "EC PRIVATE KEY";
|
||||||
}
|
}
|
||||||
|
|
||||||
DER_Encoder encoder;
|
DER_Encoder encoder;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class QSSH_EXPORT SshKeyGenerator
|
|||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator)
|
Q_DECLARE_TR_FUNCTIONS(SshKeyGenerator)
|
||||||
public:
|
public:
|
||||||
enum KeyType { Rsa, Dsa };
|
enum KeyType { Rsa, Dsa, Ecdsa };
|
||||||
enum PrivateKeyFormat { Pkcs8, OpenSsl, Mixed };
|
enum PrivateKeyFormat { Pkcs8, OpenSsl, Mixed };
|
||||||
enum EncryptionMode { DoOfferEncryption, DoNotOfferEncryption }; // Only relevant for Pkcs8 format.
|
enum EncryptionMode { DoOfferEncryption, DoNotOfferEncryption }; // Only relevant for Pkcs8 format.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user