Welcome to mirror list, hosted at ThFree Co, Russian Federation.

authplugin.but « doc - github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 41bc0daac297940bbec34b7c8f6a7ee0a6a4dc17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
\A{authplugin} PuTTY authentication plugin protocol

This appendix contains the specification for the protocol spoken over
local IPC between PuTTY and an authentication helper plugin.

If you already have an authentication plugin and want to configure
PuTTY to use it, see \k{config-ssh-authplugin} for how to do that.
This appendix is for people writing new authentication plugins.

\H{authplugin-req} Requirements

The following requirements informed the specification of this protocol.

\s{Automate keyboard-interactive authentication.} We're motivated in
the first place by the observation that the general SSH userauth
method \cq{keyboard-interactive} (defined in \k{authplugin-ref-ki})
can be used for many kinds of challenge/response or one-time-password
styles of authentication, and in more than one of those, the necessary
responses might be obtained from an auxiliary network connection, such
as an HTTPS transaction. So it's useful if a user doesn't have to
manually copy-type or copy-paste from their web browser into their SSH
client, but instead, the process can be automated.

\s{Be able to pass prompts on to the user.} On the other hand, some
userauth methods can be only \e{partially} automated; some of the
server's prompts might still require human input. Also, the plugin
automating the authentication might need to ask its own questions that
are not provided by the SSH server. (For example, \q{please enter the
master key that the real response will be generated by hashing}.) So
after the plugin intercepts the server's questions, it needs to be
able to ask its own questions of the user, which may or may not be the
same questions sent by the server.

\s{Allow automatic generation of the username.} Sometimes, the
authentication method comes with a mechanism for discovering the
username to be used in the SSH login. So the plugin has to start up
early enough that the client hasn't committed to a username yet.

\s{Future expansion route to other SSH userauth flavours.} The initial
motivation for this protocol is specific to keyboard-interactive. But
other SSH authentication methods exist, and they may also benefit from
automation in future. We're making no attempt here to predict what
those methods might be or how they might be automated, but we do need
to leave a space where they can be slotted in later if necessary.

\s{Minimal information loss.} Keyboard-interactive prompts and replies
should be passed to and from the plugin in a form as close as possible
to the way they look on the wire in SSH itself. Therefore, the
protocol resembles SSH in its data formats and marshalling (instead
of, for example, translating from SSH binary packet style to another
well-known format such as JSON, which would introduce edge cases in
character encoding).

\s{Half-duplex.} Simultaneously trying to read one I/O stream and
write another adds a lot of complexity to software. It becomes
necessary to have an organised event loop containing \cw{select} or
\cw{WaitForMultipleObjects} or similar, which can invoke the handler
for whichever event happens soonest. There's no need to add that
complexity in an application like this, which isn't transferring large
amounts of bulk data or multiplexing unrelated activities. So, to keep
life simple for plugin authors, we set the ground rule that it must
always be 100% clear which side is supposed to be sending a message
next. That way, the plugin can be written as sequential code
progressing through the protocol, making simple read and write calls
to receive or send each message.

\s{Communicate success/failure, to facilitate caching in the plugin.}
A plugin might want to cache recently used data for next time, but
only in the case where authentication using that data was actually
successful. So the client has to tell the plugin what the outcome was,
if it's known. (But this is best-effort only. Obviously the plugin
cannot \e{depend} on hearing the answer, because any IPC protocol at
all carries the risk that the other end might crash or be killed by
things outside its control.)

\H{authplugin-transport} Transport and configuration

Plugins are executable programs on the client platform.

The SSH client must be manually configured to use a plugin for a
particular connection. The configuration takes the form of a command
line, including the location of the plugin executable, and optionally
command-line arguments that are meaningful to the particular plugin.

The client invokes the plugin as a subprocess, passing it a pair of
8-bit-clean pipes as its standard input and output. On those pipes,
the client and plugin will communicate via the protocol specified
below.

\H{authplugin-formats} Data formats and marshalling

This protocol borrows the low-level data formatting from SSH itself,
in particular the following wire encodings from
\k{authplugin-ref-arch} section 5:

\dt \s{byte}

\dd An integer between 0 and 0xFF inclusive, transmitted as a single
byte of binary data.

\dt \s{boolean}

\dd The values \q{true} or \q{false}, transmitted as the bytes 1 and 0
respectively.

\dt \s{uint32}

\dd An integer between 0 and 0xFFFFFFFF inclusive, transmitted as 4
bytes of binary data, in big-endian (\q{network}) byte order.

\dt \s{string}

\dd A sequence of bytes, preceded by a \s{uint32} giving the number of
bytes in the sequence. The length field does not include itself. For
example, the empty string is represented by four zero bytes (the
\s{uint32} encoding of 0); the string "AB" is represented by the six
bytes 0,0,0,2,'A','B'.

Unlike SSH itself, the protocol spoken between the client and the
plugin is unencrypted, because local inter-process pipes are assumed
to be secured by the OS kernel. So the binary packet protocol is much
simpler than SSH proper, and is similar to SFTP and the OpenSSH agent
protocol.

The data sent in each direction of the conversation consists of a
sequence of \s{messages} exchanged between the SSH client and the
plugin. Each message is encoded as a \s{string}. The contents of the
string begin with a \s{byte} giving the message type, which determines
the format of the rest of the message.

\H{authplugin-version} Protocol versioning

This protocol itself is versioned. At connection setup, the client
states the highest version number it knows how to speak, and then the
plugin responds by choosing the version number that will actually be
spoken (which may not be higher than the client's value).

Including a version number makes it possible to make breaking changes
to the protocol later.

Even version numbers represent released versions of this spec. Odd
numbers represent drafts or development versions in between releases.
A client and plugin negotiating an odd version number are not
guaranteed to interoperate; the developer testing the combination is
responsible for ensuring the two are compatible.

This document describes version 2 of the protocol, the first released
version. (The initial drafts had version 1.)

\H{authplugin-overview} Overview and sequence of events

At the very beginning of the user authentication phase of SSH, the
client launches the plugin subprocess, if one is configured. It
immediately sends the \cw{PLUGIN_INIT} message, telling the plugin
some initial information about where the SSH connection is to.

The plugin responds with \cw{PLUGIN_INIT_RESPONSE}, which may
optionally tell the SSH client what username to use.

The client begins trying to authenticate with the SSH server in the
usual way, using the username provided by the plugin (if any) or
alternatively one obtained via its normal (non-plugin) policy.

The client follows its normal policy for selecting authentication
methods to attempt. If it chooses a method that this protocol does not
cover, then the client will perform that method in its own way without
consulting the plugin.

However, if the client and server decide to attempt a method that this
protocol \e{does} cover, then the client sends \cw{PLUGIN_PROTOCOL}
specifying the SSH protocol id for the authentication method being
used. The plugin responds with \cw{PLUGIN_PROTOCOL_ACCEPT} if it's
willing to assist with this auth method, or
\cw{PLUGIN_PROTOCOL_REJECT} if it isn't.

If the plugin sends \cw{PLUGIN_PROTOCOL_REJECT}, then the client will
proceed as if the plugin were not present. Later, if another auth
method is negotiated (either because this one failed, or because it
succeeded but the server wants multiple auth methods), the client may
send a further \cw{PLUGIN_PROTOCOL} and try again.

If the plugin sends \cw{PLUGIN_PROTOCOL_ACCEPT}, then a protocol
segment begins that is specific to that auth method, terminating in
either \cw{PLUGIN_AUTH_SUCCESS} or \cw{PLUGIN_AUTH_FAILURE}. After
that, again, the client may send a further \cw{PLUGIN_PROTOCOL}.

Currently the only supported method is \cq{keyboard-interactive},
defined in \k{authplugin-ref-ki}. Once the client has announced this
to the server, the followup protocol is as follows:

Each time the server sends an \cw{SSH_MSG_USERAUTH_INFO_REQUEST}
message requesting authentication responses from the user, the SSH
client translates the message into \cw{PLUGIN_KI_SERVER_REQUEST} and
passes it on to the plugin.

At this point, the plugin may optionally send back
\cw{PLUGIN_KI_USER_REQUEST} containing prompts to be presented to the
actual user. The client will reply with a matching
\cw{PLUGIN_KI_USER_RESPONSE} after asking the user to reply to the
question(s) in the request message. The plugin can repeat this cycle
multiple times.

Once the plugin has all the information it needs to respond to the
server's authentication prompts, it sends \cw{PLUGIN_KI_SERVER_RESPONSE}
back to the client, which translates it into
\cw{SSH_MSG_USERAUTH_INFO_RESPONSE} to send on to the server.

After that, as described in \k{authplugin-ref-ki}, the server is free
to accept authentication, reject it, or send another
\cw{SSH_MSG_USERAUTH_INFO_REQUEST}. Each
\cw{SSH_MSG_USERAUTH_INFO_REQUEST} is dealt with in the same way as
above.

If the server terminates keyboard-interactive authentication with
\cw{SSH_MSG_USERAUTH_SUCCESS} or \cw{SSH_MSG_USERAUTH_FAILURE}, the
client informs the plugin by sending either \cw{PLUGIN_AUTH_SUCCESS}
or \cw{PLUGIN_AUTH_FAILURE}. \cw{PLUGIN_AUTH_SUCCESS} is sent when
\e{that particular authentication method} was successful, regardless
of whether the SSH server chooses to request further authentication
afterwards: in particular, \cw{SSH_MSG_USERAUTH_FAILURE} with the
\q{partial success} flag (see \k{authplugin-ref-userauth} section 5.1) translates
into \cw{PLUGIN_AUTH_SUCCESS}.

The plugin's standard input will close when the client no longer
requires the plugin's services, for any reason. This could be because
authentication is complete (with overall success or overall failure),
or because the user has manually aborted the session in
mid-authentication, or because the client crashed.

\H{authplugin-messages} Message formats

This section describes the format of every message in the protocol.

As described in \k{authplugin-formats}, every message starts with the same two
fields:

\b \s{uint32}: overall length of the message

\b \s{byte}: message type.

The length field does not include itself, but does include the type
code.

The following subsections each give the format of the remainder of the
message, after the type code.

The type codes themselves are defined here:

\c #define PLUGIN_INIT                   1
\c #define PLUGIN_INIT_RESPONSE          2
\c #define PLUGIN_PROTOCOL               3
\c #define PLUGIN_PROTOCOL_ACCEPT        4
\c #define PLUGIN_PROTOCOL_REJECT        5
\c #define PLUGIN_AUTH_SUCCESS           6
\c #define PLUGIN_AUTH_FAILURE           7
\c #define PLUGIN_INIT_FAILURE           8
\c
\c #define PLUGIN_KI_SERVER_REQUEST     20
\c #define PLUGIN_KI_SERVER_RESPONSE    21
\c #define PLUGIN_KI_USER_REQUEST       22
\c #define PLUGIN_KI_USER_RESPONSE      23

If this protocol is extended to be able to assist with further auth
methods, their message type codes will also begin from 20, overlapping
the codes for keyboard-interactive.

\S{PLUGIN_INIT} \cw{PLUGIN_INIT}

\s{Direction}: client to plugin

\s{When}: the first message sent at connection startup

\s{What happens next}: the plugin will send \cw{PLUGIN_INIT_RESPONSE}
or \cw{PLUGIN_INIT_FAILURE}

\s{Message contents after the type code}:

\b \s{uint32}: the highest version number of this protocol that the
client knows how to speak.

\b \s{string}: the hostname of the server. This will be the \e{logical}
hostname, in cases where it differs from the physical destination of
the network connection. Whatever name would be used by the SSH client
to cache the server's host key, that's the same name passed in this
message.

\b \s{uint32}: the port number on the server. (Together with the host
name, this forms a primary key identifying a particular server. Port
numbers may be vital because a single host can run two unrelated SSH
servers with completely different authentication requirements, e.g.
system sshd on port 22 and Gerrit on port 29418.)

\b \s{string}: the username that the client will use to log in, if the
plugin chooses not to override it. An empty string means that the
client has no opinion about this (and might, for example, prompt the
user).

\S{PLUGIN_INIT_RESPONSE} \cw{PLUGIN_INIT_RESPONSE}

\s{Direction}: plugin to client

\s{When}: response to \cw{PLUGIN_INIT}

\s{What happens next}: the client will send \cw{PLUGIN_PROTOCOL}, or
perhaps terminate the session (if no auth method is ever negotiated
that the plugin can help with)

\s{Message contents after the type code}:

\b \s{uint32}: the version number of this protocol that the connection
will use. Must be no greater than the max version number sent by the
client in \cw{PLUGIN_INIT}.

\b \s{string}: the username that the plugin suggests the client use. An
empty string means that the plugin has no opinion and the client
should stick with the username it already had (or prompt the user, if
it had none).

\S{PLUGIN_INIT_FAILURE} \cw{PLUGIN_INIT_FAILURE}

\s{Direction}: plugin to client

\s{When}: response to \cw{PLUGIN_INIT}

\s{What happens next}: the session is over

\s{Message contents after the type code}:

\b \s{string}: an error message to present to the user indicating why
the plugin was unable to start up.

\S{PLUGIN_PROTOCOL} \cw{PLUGIN_PROTOCOL}

\s{Direction}: client to plugin

\s{When}: sent after \cw{PLUGIN_INIT_RESPONSE}, or after a previous
auth phase terminates with \cw{PLUGIN_AUTH_SUCCESS} or
\cw{PLUGIN_AUTH_FAILURE}

\s{What happens next}: the plugin will send
\cw{PLUGIN_PROTOCOL_ACCEPT} or \cw{PLUGIN_PROTOCOL_REJECT}

\s{Message contents after the type code}:

\b \s{string}: the SSH protocol id of the auth method the client
intends to attempt. Currently the only method specified for use in
this protocol is \cq{keyboard-interactive}.

\S{PLUGIN_PROTOCOL_REJECT} \cw{PLUGIN_PROTOCOL_REJECT}

\s{Direction}: plugin to client

\s{When}: sent after \cw{PLUGIN_PROTOCOL}

\s{What happens next}: the client will either send another
\cw{PLUGIN_PROTOCOL} or terminate the session

\s{Message contents after the type code}:

\b \s{string}: an error message to present to the user, explaining why
the plugin cannot help with this authentication protocol.

\lcont{

An example might be \q{unable to open <config file>: <OS error
message>}, if the plugin depends on some configuration that the user
has not set up.

If the plugin does not support this this particular authentication
protocol at all, this string should be left blank, so that no message
will be presented to the user at all.

}

\S{PLUGIN_PROTOCOL_ACCEPT} \cw{PLUGIN_PROTOCOL_ACCEPT}

\s{Direction}: plugin to client

\s{When}: sent after \cw{PLUGIN_PROTOCOL}

\s{What happens next}: depends on the auth protocol agreed on. For
keyboard-interactive, the client will send
\cw{PLUGIN_KI_SERVER_REQUEST} or \cw{PLUGIN_AUTH_SUCCESS} or
\cw{PLUGIN_AUTH_FAILURE}. No other method is specified.

\s{Message contents after the type code}: none.

\S{PLUGIN_KI_SERVER_REQUEST} \cw{PLUGIN_KI_SERVER_REQUEST}

\s{Direction}: client to plugin

\s{When}: sent after \cw{PLUGIN_PROTOCOL}, or after a previous
\cw{PLUGIN_KI_SERVER_RESPONSE}, when the SSH server has sent
\cw{SSH_MSG_USERAUTH_INFO_REQUEST}

\s{What happens next}: the plugin will send either
\cw{PLUGIN_KI_USER_REQUEST} or \cw{PLUGIN_KI_SERVER_RESPONSE}

\s{Message contents after the type code}: the exact contents of the
\cw{SSH_MSG_USERAUTH_INFO_REQUEST} just sent by the server. See
\k{authplugin-ref-ki} section 3.2 for details. The summary:

\b \s{string}: name of this prompt collection (e.g. to use as a
dialog-box title)

\b \s{string}: instructions to be displayed before this prompt
collection

\b \s{string}: language tag (deprecated)

\b \s{uint32}: number of prompts in this collection

\b That many copies of:

\lcont{

\b \s{string}: prompt (in UTF-8)

\b \s{boolean}: whether the response to this prompt is safe to echo to
the screen

}

\S{PLUGIN_KI_SERVER_RESPONSE} \cw{PLUGIN_KI_SERVER_RESPONSE}

\s{Direction}: plugin to client

\s{When}: response to \cw{PLUGIN_KI_SERVER_REQUEST}, perhaps after one
or more intervening pairs of \cw{PLUGIN_KI_USER_REQUEST} and
\cw{PLUGIN_KI_USER_RESPONSE}

\s{What happens next}: the client will send a further
\cw{PLUGIN_KI_SERVER_REQUEST}, or \cw{PLUGIN_AUTH_SUCCESS} or
\cw{PLUGIN_AUTH_FAILURE}

\s{Message contents after the type code}: the exact contents of the
\cw{SSH_MSG_USERAUTH_INFO_RESPONSE} that the client should send back
to the server. See \k{authplugin-ref-ki} section 3.4 for details. The
summary:

\b \s{uint32}: number of responses (must match the \q{number of
prompts} field from the corresponding server request)

\b That many copies of:

\lcont{

\b \s{string}: response to the \e{n}th prompt (in UTF-8)

}

\S{PLUGIN_KI_USER_REQUEST} \cw{PLUGIN_KI_USER_REQUEST}

\s{Direction}: plugin to client

\s{When}: response to \cw{PLUGIN_KI_SERVER_REQUEST}, if the plugin
cannot answer the server's auth prompts without presenting prompts of
its own to the user

\s{What happens next}: the client will send \cw{PLUGIN_KI_USER_RESPONSE}

\s{Message contents after the type code}: exactly the same as in
\cw{PLUGIN_KI_SERVER_REQUEST} (see \k{PLUGIN_KI_SERVER_REQUEST}).

\S{PLUGIN_KI_USER_RESPONSE} \cw{PLUGIN_KI_USER_RESPONSE}

\s{Direction}: client to plugin

\s{When}: response to \cw{PLUGIN_KI_USER_REQUEST}

\s{What happens next}: the plugin will send
\cw{PLUGIN_KI_SERVER_RESPONSE}, or another \cw{PLUGIN_KI_USER_REQUEST}

\s{Message contents after the type code}: exactly the same as in
\cw{PLUGIN_KI_SERVER_RESPONSE} (see \k{PLUGIN_KI_SERVER_RESPONSE}).

\S{PLUGIN_AUTH_SUCCESS} \cw{PLUGIN_AUTH_SUCCESS}

\s{Direction}: client to plugin

\s{When}: sent after \cw{PLUGIN_KI_SERVER_RESPONSE}, or (in unusual
cases) after \cw{PLUGIN_PROTOCOL_ACCEPT}

\s{What happens next}: the client will either send another
\cw{PLUGIN_PROTOCOL} or terminate the session

\s{Message contents after the type code}: none

\S{PLUGIN_AUTH_FAILURE} \cw{PLUGIN_AUTH_FAILURE}

\s{Direction}: client to plugin

\s{When}: sent after \cw{PLUGIN_KI_SERVER_RESPONSE}, or (in unusual
cases) after \cw{PLUGIN_PROTOCOL_ACCEPT}

\s{What happens next}: the client will either send another
\cw{PLUGIN_PROTOCOL} or terminate the session

\s{Message contents after the type code}: none

\H{authplugin-refs} References

\B{authplugin-ref-arch} \W{https://www.rfc-editor.org/rfc/rfc4251}{RFC 4251}, \q{The Secure Shell (SSH) Protocol
Architecture}.

\B{authplugin-ref-userauth} \W{https://www.rfc-editor.org/rfc/rfc4252}{RFC
4252}, \q{The Secure Shell (SSH) Authentication Protocol}.

\B{authplugin-ref-ki}
\W{https://www.rfc-editor.org/rfc/rfc4256}{RFC 4256},
\q{Generic Message Exchange Authentication for the Secure Shell
Protocol (SSH)} (better known by its wire id
\q{keyboard-interactive}).

\BR{authplugin-ref-arch} [RFC4251]

\BR{authplugin-ref-userauth} [RFC4252]

\BR{authplugin-ref-ki} [RFC4256]