X Tutup
Skip to content

Commit 2d15900

Browse files
Merge pull request #1888 from julianmesa-gitkraken/fix-rsa-sha1-update-libssh2
RSA SHA2 256/512 key upgrade support RFC 8332 #536 (#626)
2 parents bae468c + 089f1e4 commit 2d15900

27 files changed

+927
-27
lines changed

.jshintrc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
2+
"esversion": 9,
23
"boss": true,
34
"curly": true,
45
"eqnull": true,
5-
"esnext": true,
66
"evil": true,
77
"futurehostile": true,
88
"globals": {
@@ -16,7 +16,7 @@
1616
"it": true
1717
},
1818
"immed": false,
19-
"maxlen": 80,
19+
"maxlen": 120,
2020
"node": true,
2121
"predef": [
2222
"Promise",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"coveralls": "^3.0.2",
5959
"istanbul": "^0.4.5",
6060
"js-beautify": "~1.5.10",
61-
"jshint": "^2.9.6",
61+
"jshint": "^2.10.0",
6262
"lcov-result-merger": "^3.1.0",
6363
"mocha": "^5.2.0",
6464
"walk": "^2.3.9"

test/tests/clone.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ var assert = require("assert");
33
var fse = require("fs-extra");
44
var local = path.join.bind(path, __dirname);
55
var _ = require("lodash");
6+
const util = require("util");
7+
const exec = util.promisify(require("child_process").exec);
8+
69

710
const generatePathWithLength = (base, length) => {
811
let path = `${base}/`;
@@ -286,6 +289,62 @@ describe("Clone", function() {
286289
});
287290
});
288291

292+
if (process.platform === "win32") {
293+
it("can clone with ssh using old agent with sha1 signing support only",
294+
async function () {
295+
var pageant = local("../../vendor/pageant.exe");
296+
var old_pageant = local("../../vendor/pageant_sha1.exe");
297+
var privateKey = local("../../vendor/private.ppk");
298+
var test = this;
299+
var url = "git@github.com:nodegit/test.git";
300+
var opts = {
301+
fetchOpts: {
302+
callbacks: {
303+
certificateCheck: () => 0,
304+
credentials: function(url, userName) {
305+
return NodeGit.Credential.sshKeyFromAgent(userName);
306+
}
307+
}
308+
}
309+
};
310+
311+
try {
312+
await exec("taskkill /im pageant.exe /f /t");
313+
} catch (e) {
314+
try {
315+
await exec("taskkill /im pageant_sha1.exe /f /t");
316+
} catch(e) {}
317+
}
318+
try {
319+
await exec(`powershell -command "Start-Process ${old_pageant} ${privateKey}`);
320+
} catch (e) {
321+
try {
322+
await exec(`powershell -command "Start-Process ${pageant} ${privateKey}`);
323+
} catch (e) {}
324+
return assert.fail("Cannot run old pageant");
325+
}
326+
327+
try {
328+
const repo = await Clone(url, clonePath, opts);
329+
test.repository = repo;
330+
} catch(e) {
331+
return assert.fail("Clone error: " + e.message);
332+
}
333+
334+
try {
335+
await exec("taskkill /im pageant_sha1.exe /f /t");
336+
} catch(e) {}
337+
338+
try {
339+
await exec(`powershell -command "Start-Process ${pageant} ${privateKey}`);
340+
} catch (e) {
341+
return assert.fail("Cannot run pageant");
342+
}
343+
344+
return assert.ok(test.repository instanceof Repository);
345+
});
346+
}
347+
289348
it("can clone with ssh", function() {
290349
var test = this;
291350
var url = "git@github.com:nodegit/test.git";

vendor/libssh2/docs/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ set(MAN_PAGES
193193
libssh2_trace.3
194194
libssh2_trace_sethandler.3
195195
libssh2_userauth_authenticated.3
196+
libssh2_userauth_banner.3
196197
libssh2_userauth_hostbased_fromfile.3
197198
libssh2_userauth_hostbased_fromfile_ex.3
198199
libssh2_userauth_keyboard_interactive.3

vendor/libssh2/docs/HACKING-CRYPTO

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,32 @@ Note: this procedure is not used if macro _libssh2_rsa_sha1_signv() is defined.
637637
void _libssh2_rsa_free(libssh2_rsa_ctx *rsactx);
638638
Releases the RSA computation context at rsactx.
639639

640+
LIBSSH2_RSA_SHA2
641+
#define as 1 if the crypto library supports RSA SHA2 256/512, else 0.
642+
If defined as 0, the rest of this section can be omitted.
643+
644+
int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
645+
libssh2_rsa_ctx * rsactx,
646+
const unsigned char *hash,
647+
size_t hash_len,
648+
unsigned char **signature,
649+
size_t *signature_len);
650+
RSA signs the (hash, hashlen) SHA-2 hash bytes based on hash length and stores
651+
the allocated signature at (signature, signature_len).
652+
Signature buffer must be allocated from the given session.
653+
Returns 0 if OK, else -1.
654+
This procedure is already prototyped in crypto.h.
655+
Note: this procedure is not used if macro _libssh2_rsa_sha1_signv() is defined.
656+
657+
int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa,
658+
size_t hash_len,
659+
const unsigned char *sig,
660+
unsigned long sig_len,
661+
const unsigned char *m, unsigned long m_len);
662+
Verify (sig, sig_len) signature of (m, m_len) using an SHA-2 hash based on
663+
hash length and the RSA context.
664+
Return 0 if OK, else -1.
665+
This procedure is already prototyped in crypto.h.
640666

641667
7.2) DSA
642668
LIBSSH2_DSA
@@ -900,3 +926,14 @@ If this is not needed, it should be defined as an empty macro.
900926
int _libssh2_random(unsigned char *buf, int len);
901927
Store len random bytes at buf.
902928
Returns 0 if OK, else -1.
929+
930+
const char * _libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
931+
unsigned char *key_method,
932+
size_t key_method_len);
933+
934+
This function is for implementing key hash upgrading as defined in RFC 8332.
935+
936+
Based on the incoming key_method value, this function will return a
937+
list of supported algorithms that can upgrade the original key method algorithm
938+
as a comma seperated list, if there is no upgrade option this function should
939+
return NULL.

vendor/libssh2/docs/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ dist_man_MANS = \
163163
libssh2_trace.3 \
164164
libssh2_trace_sethandler.3 \
165165
libssh2_userauth_authenticated.3 \
166+
libssh2_userauth_banner.3 \
166167
libssh2_userauth_hostbased_fromfile.3 \
167168
libssh2_userauth_hostbased_fromfile_ex.3 \
168169
libssh2_userauth_keyboard_interactive.3 \

vendor/libssh2/docs/libssh2_session_methods.3

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.TH libssh2_session_methods 3 "1 Jun 2007" "libssh2 0.15" "libssh2 manual"
1+
.TH libssh2_session_methods 3 "8 Nov 2021" "libssh2 1.11" "libssh2 manual"
22
.SH NAME
33
libssh2_session_methods - return the currently active algorithms
44
.SH SYNOPSIS
@@ -8,13 +8,14 @@ const char *
88
libssh2_session_methods(LIBSSH2_SESSION *session, int method_type);
99

1010
.SH DESCRIPTION
11-
\fIsession\fP - Session instance as returned by
11+
\fIsession\fP - Session instance as returned by
1212
.BR libssh2_session_init_ex(3)
1313

1414
\fImethod_type\fP - one of the method type constants: LIBSSH2_METHOD_KEX,
1515
LIBSSH2_METHOD_HOSTKEY, LIBSSH2_METHOD_CRYPT_CS, LIBSSH2_METHOD_CRYPT_SC,
1616
LIBSSH2_METHOD_MAC_CS, LIBSSH2_METHOD_MAC_SC, LIBSSH2_METHOD_COMP_CS,
17-
LIBSSH2_METHOD_COMP_SC, LIBSSH2_METHOD_LANG_CS, LIBSSH2_METHOD_LANG_SC.
17+
LIBSSH2_METHOD_COMP_SC, LIBSSH2_METHOD_LANG_CS, LIBSSH2_METHOD_LANG_SC,
18+
LIBSSH2_METHOD_SIGN_ALGO.
1819

1920
Returns the actual method negotiated for a particular transport parameter.
2021
.SH RETURN VALUE
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
.TH libssh2_userauth_banner 3 "1 Jun 2021" "libssh2 1.9.0" "libssh2 manual"
2+
.SH NAME
3+
libssh2_userauth_banner - get the server's userauth banner message
4+
.SH SYNOPSIS
5+
.nf
6+
#include <libssh2.h>
7+
8+
int
9+
libssh2_userauth_banner(LIBSSH2_SESSION *session, char **banner);
10+
.SH DESCRIPTION
11+
\fIsession\fP - Session instance as returned by
12+
.BR libssh2_session_init_ex(3)
13+
14+
\fIbanner\fP - Should point to a pointer that gets filled with banner message.
15+
16+
After an authentication has been attempted, such as a
17+
\fBSSH_USERAUTH_NONE\fP request sent by
18+
.BR libssh2_userauth_list(3) ,
19+
this function can be called to retrieve the userauth banner sent by
20+
the server. If no such banner is sent, or if an authentication has not
21+
yet been attempted, returns LIBSSH2_ERROR_MISSING_USERAUTH_BANNER.
22+
.SH RETURN VALUE
23+
On success returns 0 and an UTF-8 NUL-terminated string is stored in the
24+
\fIbanner\fP. This string is internally managed by libssh2 and will be
25+
deallocated upon session termination.
26+
On failure returns
27+
LIBSSH2_ERROR_MISSING_USERAUTH_BANNER.
28+
.SH SEE ALSO
29+
.BR libssh2_session_init_ex(3),
30+
.BR libssh2_userauth_list(3)

vendor/libssh2/include/libssh2.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE
356356
#define LIBSSH2_METHOD_COMP_SC 7
357357
#define LIBSSH2_METHOD_LANG_CS 8
358358
#define LIBSSH2_METHOD_LANG_SC 9
359+
#define LIBSSH2_METHOD_SIGN_ALGO 10
359360

360361
/* flags */
361362
#define LIBSSH2_FLAG_SIGPIPE 1
@@ -506,6 +507,8 @@ typedef struct _LIBSSH2_POLLFD {
506507
#define LIBSSH2_ERROR_CHANNEL_WINDOW_FULL -47
507508
#define LIBSSH2_ERROR_KEYFILE_AUTH_FAILED -48
508509
#define LIBSSH2_ERROR_RANDGEN -49
510+
#define LIBSSH2_ERROR_MISSING_USERAUTH_BANNER -50
511+
#define LIBSSH2_ERROR_ALGO_UNSUPPORTED -51
509512

510513
/* this is a define to provide the old (<= 1.2.7) name */
511514
#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV
@@ -614,6 +617,8 @@ LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session);
614617
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session,
615618
const char *username,
616619
unsigned int username_len);
620+
LIBSSH2_API int libssh2_userauth_banner(LIBSSH2_SESSION *session,
621+
char **banner);
617622
LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session);
618623

619624
LIBSSH2_API int

vendor/libssh2/src/agent.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@
9494
#define SSH_AGENT_CONSTRAIN_LIFETIME 1
9595
#define SSH_AGENT_CONSTRAIN_CONFIRM 2
9696

97+
/* Signature request methods */
98+
#define SSH_AGENT_RSA_SHA2_256 2
99+
#define SSH_AGENT_RSA_SHA2_512 4
100+
97101
#ifdef PF_UNIX
98102
static int
99103
agent_connect_unix(LIBSSH2_AGENT *agent)
@@ -375,6 +379,8 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
375379
ssize_t method_len;
376380
unsigned char *s;
377381
int rc;
382+
unsigned char *method_name;
383+
uint32_t sign_flags = 0;
378384

379385
/* Create a request to sign the data */
380386
if(transctx->state == agent_NB_state_init) {
@@ -391,7 +397,18 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
391397
_libssh2_store_str(&s, (const char *)data, data_len);
392398

393399
/* flags */
394-
_libssh2_store_u32(&s, 0);
400+
if(session->userauth_pblc_method_len > 0 &&
401+
session->userauth_pblc_method) {
402+
if(session->userauth_pblc_method_len == 12 &&
403+
!memcmp(session->userauth_pblc_method, "rsa-sha2-512", 12)) {
404+
sign_flags = SSH_AGENT_RSA_SHA2_512;
405+
}
406+
else if(session->userauth_pblc_method_len == 12 &&
407+
!memcmp(session->userauth_pblc_method, "rsa-sha2-256", 12)) {
408+
sign_flags = SSH_AGENT_RSA_SHA2_256;
409+
}
410+
}
411+
_libssh2_store_u32(&s, sign_flags);
395412

396413
transctx->request_len = s - transctx->request;
397414
transctx->send_recv_total = 0;
@@ -449,8 +466,38 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
449466
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
450467
goto error;
451468
}
469+
470+
/* method name */
471+
method_name = LIBSSH2_ALLOC(session, method_len);
472+
if(!method_name) {
473+
rc = LIBSSH2_ERROR_ALLOC;
474+
goto error;
475+
}
476+
memcpy(method_name, s, method_len);
452477
s += method_len;
453478

479+
/* check to see if we match requested */
480+
if((size_t)method_len == session->userauth_pblc_method_len) {
481+
if(memcmp(method_name, session->userauth_pblc_method, method_len)) {
482+
_libssh2_debug(session,
483+
LIBSSH2_TRACE_KEX,
484+
"Agent sign method %.*s",
485+
method_len, method_name);
486+
487+
rc = LIBSSH2_ERROR_ALGO_UNSUPPORTED;
488+
goto error;
489+
}
490+
}
491+
else {
492+
_libssh2_debug(session,
493+
LIBSSH2_TRACE_KEX,
494+
"Agent sign method %.*s",
495+
method_len, method_name);
496+
497+
rc = LIBSSH2_ERROR_ALGO_UNSUPPORTED;
498+
goto error;
499+
}
500+
454501
/* Read the signature */
455502
len -= 4;
456503
if(len < 0) {
@@ -479,6 +526,8 @@ agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
479526
LIBSSH2_FREE(session, transctx->response);
480527
transctx->response = NULL;
481528

529+
transctx->state = agent_NB_state_init;
530+
482531
return _libssh2_error(session, rc, "agent sign failure");
483532
}
484533

0 commit comments

Comments
 (0)
X Tutup