aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <[email protected]>2015-07-22 16:26:05 +0200
committerChristian Kandeler <[email protected]>2015-07-27 13:08:44 +0000
commitac0e66d9e04e196f4b3a46cd709cb76aafbd45fe (patch)
tree7ced42883d1e6fd411eb2ab94808978593e42a84
parent8f5618c3ecc0daf971b19780646cc14a6db12931 (diff)
SSH: Support creation of ECDSA keys.
Change-Id: Id5b5ed289a3fd86bd8b84e6429c18f417ca793a7 Reviewed-by: Leena Miettinen <[email protected]> Reviewed-by: Joerg Bornemann <[email protected]>
-rw-r--r--src/libs/ssh/sshcryptofacility.cpp14
-rw-r--r--src/libs/ssh/sshkeycreationdialog.cpp17
-rw-r--r--src/libs/ssh/sshkeycreationdialog.ui26
-rw-r--r--src/libs/ssh/sshkeygenerator.cpp49
-rw-r--r--src/libs/ssh/sshkeygenerator.h2
5 files changed, 72 insertions, 36 deletions
diff --git a/src/libs/ssh/sshcryptofacility.cpp b/src/libs/ssh/sshcryptofacility.cpp
index 227c8df3ab5..4dc27929f86 100644
--- a/src/libs/ssh/sshcryptofacility.cpp
+++ b/src/libs/ssh/sshcryptofacility.cpp
@@ -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;
diff --git a/src/libs/ssh/sshkeycreationdialog.cpp b/src/libs/ssh/sshkeycreationdialog.cpp
index 80118cde5ac..348a8423649 100644
--- a/src/libs/ssh/sshkeycreationdialog.cpp
+++ b/src/libs/ssh/sshkeycreationdialog.cpp
@@ -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;
diff --git a/src/libs/ssh/sshkeycreationdialog.ui b/src/libs/ssh/sshkeycreationdialog.ui
index d49681e65b9..eb3347e8ee8 100644
--- a/src/libs/ssh/sshkeycreationdialog.ui
+++ b/src/libs/ssh/sshkeycreationdialog.ui
@@ -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">
@@ -68,6 +68,13 @@
</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">
<enum>Qt::Horizontal</enum>
@@ -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>
diff --git a/src/libs/ssh/sshkeygenerator.cpp b/src/libs/ssh/sshkeygenerator.cpp
index d70819e97e4..1c6e22db038 100644
--- a/src/libs/ssh/sshkeygenerator.cpp
+++ b/src/libs/ssh/sshkeygenerator.cpp
@@ -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;
diff --git a/src/libs/ssh/sshkeygenerator.h b/src/libs/ssh/sshkeygenerator.h
index 7092eceb12c..df9ac41518a 100644
--- a/src/libs/ssh/sshkeygenerator.h
+++ b/src/libs/ssh/sshkeygenerator.h
@@ -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.