keepassxc

Форк
0
/
TestSSHAgent.cpp 
297 строк · 8.8 Кб
1
/*
2
 *  Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
3
 *
4
 *  This program is free software: you can redistribute it and/or modify
5
 *  it under the terms of the GNU General Public License as published by
6
 *  the Free Software Foundation, either version 2 or (at your option)
7
 *  version 3 of the License.
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17

18
#include "TestSSHAgent.h"
19
#include "config-keepassx-tests.h"
20
#include "core/Config.h"
21
#include "crypto/Crypto.h"
22
#include "sshagent/KeeAgentSettings.h"
23
#include "sshagent/OpenSSHKeyGen.h"
24
#include "sshagent/SSHAgent.h"
25

26
#include <QTest>
27

28
QTEST_GUILESS_MAIN(TestSSHAgent)
29

30
void TestSSHAgent::initTestCase()
31
{
32
    QVERIFY(Crypto::init());
33
    Config::createTempFileInstance();
34

35
    m_agentSocketFile.setAutoRemove(true);
36
    QVERIFY(m_agentSocketFile.open());
37

38
    m_agentSocketFileName = m_agentSocketFile.fileName();
39
    QVERIFY(!m_agentSocketFileName.isEmpty());
40

41
    // let ssh-agent re-create it as a socket
42
    QVERIFY(m_agentSocketFile.remove());
43

44
    QStringList arguments;
45
    arguments << "-D"
46
              << "-a" << m_agentSocketFileName;
47

48
    QElapsedTimer timer;
49
    timer.start();
50

51
    qDebug() << "ssh-agent starting with arguments" << arguments;
52
    m_agentProcess.setProcessChannelMode(QProcess::ForwardedChannels);
53
    m_agentProcess.start("ssh-agent", arguments);
54
    m_agentProcess.closeWriteChannel();
55

56
    if (!m_agentProcess.waitForStarted()) {
57
        QSKIP("ssh-agent could not be started");
58
    }
59

60
    qDebug() << "ssh-agent started as pid" << m_agentProcess.pid();
61

62
    // we need to wait for the agent to open the socket before going into real tests
63
    QFileInfo socketFileInfo(m_agentSocketFileName);
64
    while (!timer.hasExpired(2000)) {
65
        if (socketFileInfo.exists()) {
66
            break;
67
        }
68
        QTest::qWait(10);
69
    }
70

71
    QVERIFY(socketFileInfo.exists());
72
    qDebug() << "ssh-agent initialized in" << timer.elapsed() << "ms";
73

74
    // initialize test key
75
    const QString keyString = QString("-----BEGIN OPENSSH PRIVATE KEY-----\n"
76
                                      "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n"
77
                                      "QyNTUxOQAAACDdlO5F2kF2WzedrBAHBi9wBHeISzXZ0IuIqrp0EzeazAAAAKjgCfj94An4\n"
78
                                      "/QAAAAtzc2gtZWQyNTUxOQAAACDdlO5F2kF2WzedrBAHBi9wBHeISzXZ0IuIqrp0EzeazA\n"
79
                                      "AAAEBe1iilZFho8ZGAliiSj5URvFtGrgvmnEKdiLZow5hOR92U7kXaQXZbN52sEAcGL3AE\n"
80
                                      "d4hLNdnQi4iqunQTN5rMAAAAH29wZW5zc2hrZXktdGVzdC1wYXJzZUBrZWVwYXNzeGMBAg\n"
81
                                      "MEBQY=\n"
82
                                      "-----END OPENSSH PRIVATE KEY-----\n");
83

84
    const QByteArray keyData = keyString.toLatin1();
85

86
    QVERIFY(m_key.parsePKCS1PEM(keyData));
87
}
88

89
void TestSSHAgent::testConfiguration()
90
{
91
    SSHAgent agent;
92

93
    // default config must not enable agent
94
    QVERIFY(!agent.isEnabled());
95

96
    agent.setEnabled(true);
97
    QVERIFY(agent.isEnabled());
98

99
    // this will either be an empty string or the real ssh-agent socket path, doesn't matter
100
    QString defaultSocketPath = agent.socketPath(false);
101

102
    // overridden path must match default before setting an override
103
    QCOMPARE(agent.socketPath(true), defaultSocketPath);
104

105
    agent.setAuthSockOverride(m_agentSocketFileName);
106

107
    // overridden path must match what we set
108
    QCOMPARE(agent.socketPath(true), m_agentSocketFileName);
109

110
    // non-overridden path must match the default
111
    QCOMPARE(agent.socketPath(false), defaultSocketPath);
112
}
113

114
void TestSSHAgent::testIdentity()
115
{
116
    SSHAgent agent;
117
    agent.setEnabled(true);
118
    agent.setAuthSockOverride(m_agentSocketFileName);
119

120
    QVERIFY(agent.isAgentRunning());
121

122
    KeeAgentSettings settings;
123
    bool keyInAgent;
124

125
    // test adding a key works
126
    QVERIFY(agent.addIdentity(m_key, settings, m_uuid));
127
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && keyInAgent);
128

129
    // test non-conflicting key ownership doesn't throw an error
130
    QVERIFY(agent.addIdentity(m_key, settings, m_uuid));
131

132
    // test conflicting key ownership throws an error
133
    QUuid secondUuid("{11111111-1111-1111-1111-111111111111}");
134
    QVERIFY(!agent.addIdentity(m_key, settings, secondUuid));
135

136
    // test removing a key works
137
    QVERIFY(agent.removeIdentity(m_key));
138
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && !keyInAgent);
139
}
140

141
void TestSSHAgent::testRemoveOnClose()
142
{
143
    SSHAgent agent;
144
    agent.setEnabled(true);
145
    agent.setAuthSockOverride(m_agentSocketFileName);
146

147
    QVERIFY(agent.isAgentRunning());
148

149
    KeeAgentSettings settings;
150
    bool keyInAgent;
151

152
    settings.setRemoveAtDatabaseClose(true);
153
    QVERIFY(agent.addIdentity(m_key, settings, m_uuid));
154
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && keyInAgent);
155
    agent.setEnabled(false);
156
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && !keyInAgent);
157
}
158

159
void TestSSHAgent::testLifetimeConstraint()
160
{
161
    SSHAgent agent;
162
    agent.setEnabled(true);
163
    agent.setAuthSockOverride(m_agentSocketFileName);
164

165
    QVERIFY(agent.isAgentRunning());
166

167
    KeeAgentSettings settings;
168
    bool keyInAgent;
169

170
    settings.setUseLifetimeConstraintWhenAdding(true);
171
    settings.setLifetimeConstraintDuration(2); // two seconds
172

173
    // identity should be in agent immediately after adding
174
    QVERIFY(agent.addIdentity(m_key, settings, m_uuid));
175
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && keyInAgent);
176

177
    QElapsedTimer timer;
178
    timer.start();
179

180
    // wait for the identity to time out
181
    while (!timer.hasExpired(5000)) {
182
        QVERIFY(agent.checkIdentity(m_key, keyInAgent));
183

184
        if (!keyInAgent) {
185
            break;
186
        }
187

188
        QTest::qWait(100);
189
    }
190

191
    QVERIFY(!keyInAgent);
192
}
193

194
void TestSSHAgent::testConfirmConstraint()
195
{
196
    SSHAgent agent;
197
    agent.setEnabled(true);
198
    agent.setAuthSockOverride(m_agentSocketFileName);
199

200
    QVERIFY(agent.isAgentRunning());
201

202
    KeeAgentSettings settings;
203
    bool keyInAgent;
204

205
    settings.setUseConfirmConstraintWhenAdding(true);
206

207
    QVERIFY(agent.addIdentity(m_key, settings, m_uuid));
208

209
    // we can't test confirmation itself is working but we can test the agent accepts the key
210
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && keyInAgent);
211

212
    QVERIFY(agent.removeIdentity(m_key));
213
    QVERIFY(agent.checkIdentity(m_key, keyInAgent) && !keyInAgent);
214
}
215

216
void TestSSHAgent::testToOpenSSHKey()
217
{
218
    KeeAgentSettings settings;
219
    settings.setSelectedType("file");
220
    settings.setFileName(QString("%1/id_rsa-encrypted-asn1").arg(QString(KEEPASSX_TEST_DATA_DIR)));
221

222
    OpenSSHKey key;
223
    settings.toOpenSSHKey("username", "correctpassphrase", QString(), nullptr, key, false);
224

225
    QVERIFY(!key.publicKey().isEmpty());
226
}
227

228
void TestSSHAgent::testKeyGenRSA()
229
{
230
    SSHAgent agent;
231
    agent.setEnabled(true);
232
    agent.setAuthSockOverride(m_agentSocketFileName);
233

234
    QVERIFY(agent.isAgentRunning());
235

236
    OpenSSHKey key;
237
    KeeAgentSettings settings;
238
    bool keyInAgent;
239

240
    QVERIFY(OpenSSHKeyGen::generateRSA(key, 2048));
241

242
    QVERIFY(agent.addIdentity(key, settings, m_uuid));
243
    QVERIFY(agent.checkIdentity(key, keyInAgent) && keyInAgent);
244
    QVERIFY(agent.removeIdentity(key));
245
    QVERIFY(agent.checkIdentity(key, keyInAgent) && !keyInAgent);
246
}
247

248
void TestSSHAgent::testKeyGenECDSA()
249
{
250
    SSHAgent agent;
251
    agent.setEnabled(true);
252
    agent.setAuthSockOverride(m_agentSocketFileName);
253

254
    QVERIFY(agent.isAgentRunning());
255

256
    OpenSSHKey key;
257
    KeeAgentSettings settings;
258
    bool keyInAgent;
259

260
    QVERIFY(OpenSSHKeyGen::generateECDSA(key, 256));
261

262
    QVERIFY(agent.addIdentity(key, settings, m_uuid));
263
    QVERIFY(agent.checkIdentity(key, keyInAgent) && keyInAgent);
264
    QVERIFY(agent.removeIdentity(key));
265
    QVERIFY(agent.checkIdentity(key, keyInAgent) && !keyInAgent);
266
}
267

268
void TestSSHAgent::testKeyGenEd25519()
269
{
270
    SSHAgent agent;
271
    agent.setEnabled(true);
272
    agent.setAuthSockOverride(m_agentSocketFileName);
273

274
    QVERIFY(agent.isAgentRunning());
275

276
    OpenSSHKey key;
277
    KeeAgentSettings settings;
278
    bool keyInAgent;
279

280
    QVERIFY(OpenSSHKeyGen::generateEd25519(key));
281

282
    QVERIFY(agent.addIdentity(key, settings, m_uuid));
283
    QVERIFY(agent.checkIdentity(key, keyInAgent) && keyInAgent);
284
    QVERIFY(agent.removeIdentity(key));
285
    QVERIFY(agent.checkIdentity(key, keyInAgent) && !keyInAgent);
286
}
287

288
void TestSSHAgent::cleanupTestCase()
289
{
290
    if (m_agentProcess.state() != QProcess::NotRunning) {
291
        qDebug() << "Killing ssh-agent pid" << m_agentProcess.pid();
292
        m_agentProcess.terminate();
293
        m_agentProcess.waitForFinished();
294
    }
295

296
    m_agentSocketFile.remove();
297
}
298

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.