summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@theqtcompany.com>2015-07-21 14:10:48 +0200
committerChristian Kandeler <christian.kandeler@theqtcompany.com>2015-07-21 16:13:42 +0000
commitfbc968972379739a5d2dbd7de5cc1ddd0e3b5f0d (patch)
tree5ec1dbc2f2f0e8b9d848d0c91428b47e84f4c08f
parent815caedceb9ea0075292e00639d12104be287aba (diff)
downloadqt-creator-fbc968972379739a5d2dbd7de5cc1ddd0e3b5f0d.tar.gz
SSH: Support ECDSA user keys.
In the default format of ssh-keygen. Change-Id: Ibea5f4bde5cc6ea343f75c73f786437178e4350e Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
-rw-r--r--src/libs/ssh/sshcryptofacility.cpp57
-rw-r--r--src/libs/ssh/sshcryptofacility_p.h2
2 files changed, 54 insertions, 5 deletions
diff --git a/src/libs/ssh/sshcryptofacility.cpp b/src/libs/ssh/sshcryptofacility.cpp
index d4647b59fd..c048b42d94 100644
--- a/src/libs/ssh/sshcryptofacility.cpp
+++ b/src/libs/ssh/sshcryptofacility.cpp
@@ -177,6 +177,8 @@ const QByteArray SshEncryptionFacility::PrivKeyFileStartLineRsa("-----BEGIN RSA
const QByteArray SshEncryptionFacility::PrivKeyFileStartLineDsa("-----BEGIN DSA PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileEndLineRsa("-----END RSA PRIVATE KEY-----");
const QByteArray SshEncryptionFacility::PrivKeyFileEndLineDsa("-----END DSA PRIVATE KEY-----");
+const QByteArray SshEncryptionFacility::PrivKeyFileStartLineEcdsa("-----BEGIN EC PRIVATE KEY-----");
+const QByteArray SshEncryptionFacility::PrivKeyFileEndLineEcdsa("-----END EC PRIVATE KEY-----");
QByteArray SshEncryptionFacility::cryptAlgoName(const SshKeyExchange &kex) const
{
@@ -210,6 +212,7 @@ void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFil
if (privKeyFileContents == m_cachedPrivKeyContents)
return;
+ m_authKeyAlgoName.clear();
#ifdef CREATOR_SSH_DEBUG
qDebug("%s: Key not cached, reading", Q_FUNC_INFO);
#endif
@@ -235,8 +238,15 @@ void SshEncryptionFacility::createAuthenticationKey(const QByteArray &privKeyFil
}
m_authPubKeyBlob = AbstractSshPacket::encodeString(m_authKeyAlgoName);
- foreach (const BigInt &b, pubKeyParams)
- m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b);
+ auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data());
+ if (ecdsaKey) {
+ m_authPubKeyBlob += AbstractSshPacket::encodeString(m_authKeyAlgoName.mid(11)); // Without "ecdsa-sha2-" prefix.
+ m_authPubKeyBlob += AbstractSshPacket::encodeString(
+ convertByteArray(EC2OSP(ecdsaKey->public_point(), PointGFp::UNCOMPRESSED)));
+ } else {
+ foreach (const BigInt &b, pubKeyParams)
+ m_authPubKeyBlob += AbstractSshPacket::encodeMpInt(b);
+ }
m_cachedPrivKeyContents = privKeyFileContents;
}
@@ -294,6 +304,10 @@ bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray
syntaxOk = false;
else
m_authKeyAlgoName = SshCapabilities::PubKeyDss;
+ } else if (lines.first() == PrivKeyFileStartLineEcdsa) {
+ if (lines.last() != PrivKeyFileEndLineEcdsa)
+ syntaxOk = false;
+ // m_authKeyAlgoName set below, as we don't know the size yet.
} else {
syntaxOk = false;
}
@@ -311,8 +325,10 @@ bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray
BER_Decoder sequence = decoder.start_cons(SEQUENCE);
size_t version;
sequence.decode (version);
- if (version != 0) {
- error = SSH_TR("Key encoding has version %1, expected 0.").arg(version);
+ const size_t expectedVersion = m_authKeyAlgoName.isEmpty() ? 1 : 0;
+ if (version != expectedVersion) {
+ error = SSH_TR("Key encoding has version %1, expected %2.")
+ .arg(version).arg(expectedVersion);
return false;
}
@@ -323,13 +339,37 @@ bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray
m_authKey.reset(dsaKey);
pubKeyParams << p << q << g << y;
allKeyParams << pubKeyParams << x;
- } else {
+ } else if (m_authKeyAlgoName == SshCapabilities::PubKeyRsa) {
BigInt p, q, e, d, n;
sequence.decode(n).decode(e).decode(d).decode(p).decode(q);
RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(m_rng, p, q, e, d, n);
m_authKey.reset(rsaKey);
pubKeyParams << e << n;
allKeyParams << pubKeyParams << p << q << d;
+ } else {
+ BigInt privKey;
+ sequence.decode_octet_string_bigint(privKey);
+ switch (privKey.bytes()) {
+ case 32:
+ m_authKeyAlgoName = SshCapabilities::PubKeyEcdsa256;
+ break;
+ case 48:
+ m_authKeyAlgoName = SshCapabilities::PubKeyEcdsa384;
+ break;
+ case 66:
+ m_authKeyAlgoName = SshCapabilities::PubKeyEcdsa521;
+ break;
+ default:
+ error = SSH_TR("Unexpected ECDSA key width %1").arg(privKey.bytes());
+ return false;
+ }
+
+ const EC_Group group(SshCapabilities::oid(m_authKeyAlgoName));
+ auto * const key = new ECDSA_PrivateKey(m_rng, group, privKey);
+ m_authKey.reset(key);
+ pubKeyParams << key->public_point().get_affine_x()
+ << key->public_point().get_affine_y();
+ allKeyParams << pubKeyParams << privKey;
}
sequence.discard_remaining();
@@ -360,6 +400,13 @@ QByteArray SshEncryptionFacility::authenticationKeySignature(const QByteArray &d
QByteArray signature
= convertByteArray(signer->sign_message(convertByteArray(dataToSign),
dataToSign.size(), m_rng));
+ if (m_authKeyAlgoName.startsWith(SshCapabilities::PubKeyEcdsaPrefix)) {
+ // The Botan output is not quite in the format that SSH defines.
+ const int halfSize = signature.count() / 2;
+ const BigInt r = BigInt::decode(convertByteArray(signature), halfSize);
+ const BigInt s = BigInt::decode(convertByteArray(signature.mid(halfSize)), halfSize);
+ signature = AbstractSshPacket::encodeMpInt(r) + AbstractSshPacket::encodeMpInt(s);
+ }
return AbstractSshPacket::encodeString(m_authKeyAlgoName)
+ AbstractSshPacket::encodeString(signature);
}
diff --git a/src/libs/ssh/sshcryptofacility_p.h b/src/libs/ssh/sshcryptofacility_p.h
index 3710227455..6a69d5d833 100644
--- a/src/libs/ssh/sshcryptofacility_p.h
+++ b/src/libs/ssh/sshcryptofacility_p.h
@@ -115,6 +115,8 @@ private:
static const QByteArray PrivKeyFileStartLineDsa;
static const QByteArray PrivKeyFileEndLineRsa;
static const QByteArray PrivKeyFileEndLineDsa;
+ static const QByteArray PrivKeyFileStartLineEcdsa;
+ static const QByteArray PrivKeyFileEndLineEcdsa;
QByteArray m_authKeyAlgoName;
QByteArray m_authPubKeyBlob;