|
Lines 178-183
struct identity {
Link Here
|
| 178 |
AuthenticationConnection *ac; /* set if agent supports key */ |
178 |
AuthenticationConnection *ac; /* set if agent supports key */ |
| 179 |
Key *key; /* public/private key */ |
179 |
Key *key; /* public/private key */ |
| 180 |
char *filename; /* comment for agent-only keys */ |
180 |
char *filename; /* comment for agent-only keys */ |
|
|
181 |
char *comment; /* comment for other keys */ |
| 181 |
int tried; |
182 |
int tried; |
| 182 |
int isprivate; /* key points to the private key */ |
183 |
int isprivate; /* key points to the private key */ |
| 183 |
}; |
184 |
}; |
|
Lines 244-250
void userauth(Authctxt *, char *);
Link Here
|
| 244 |
static int sign_and_send_pubkey(Authctxt *, Identity *); |
245 |
static int sign_and_send_pubkey(Authctxt *, Identity *); |
| 245 |
static void pubkey_prepare(Authctxt *); |
246 |
static void pubkey_prepare(Authctxt *); |
| 246 |
static void pubkey_cleanup(Authctxt *); |
247 |
static void pubkey_cleanup(Authctxt *); |
| 247 |
static Key *load_identity_file(char *); |
248 |
static Key *load_identity_file(Identity *, char **); |
|
|
249 |
static void add_keys_to_agent(Authctxt *, char *); |
| 248 |
|
250 |
|
| 249 |
static Authmethod *authmethod_get(char *authlist); |
251 |
static Authmethod *authmethod_get(char *authlist); |
| 250 |
static Authmethod *authmethod_lookup(const char *name); |
252 |
static Authmethod *authmethod_lookup(const char *name); |
|
Lines 1101-1139
input_userauth_jpake_server_confirm(int
Link Here
|
| 1101 |
#endif /* JPAKE */ |
1103 |
#endif /* JPAKE */ |
| 1102 |
|
1104 |
|
| 1103 |
static int |
1105 |
static int |
| 1104 |
identity_sign(Identity *id, u_char **sigp, u_int *lenp, |
|
|
| 1105 |
u_char *data, u_int datalen) |
| 1106 |
{ |
| 1107 |
Key *prv; |
| 1108 |
int ret; |
| 1109 |
|
| 1110 |
/* the agent supports this key */ |
| 1111 |
if (id->ac) |
| 1112 |
return (ssh_agent_sign(id->ac, id->key, sigp, lenp, |
| 1113 |
data, datalen)); |
| 1114 |
/* |
| 1115 |
* we have already loaded the private key or |
| 1116 |
* the private key is stored in external hardware |
| 1117 |
*/ |
| 1118 |
if (id->isprivate || (id->key->flags & KEY_FLAG_EXT)) |
| 1119 |
return (key_sign(id->key, sigp, lenp, data, datalen)); |
| 1120 |
/* load the private key from the file */ |
| 1121 |
if ((prv = load_identity_file(id->filename)) == NULL) |
| 1122 |
return (-1); |
| 1123 |
ret = key_sign(prv, sigp, lenp, data, datalen); |
| 1124 |
key_free(prv); |
| 1125 |
return (ret); |
| 1126 |
} |
| 1127 |
|
| 1128 |
static int |
| 1129 |
sign_and_send_pubkey(Authctxt *authctxt, Identity *id) |
1106 |
sign_and_send_pubkey(Authctxt *authctxt, Identity *id) |
| 1130 |
{ |
1107 |
{ |
| 1131 |
Buffer b; |
1108 |
Buffer b; |
| 1132 |
u_char *blob, *signature; |
1109 |
u_char *blob, *signature; |
| 1133 |
u_int bloblen, slen; |
1110 |
u_int bloblen, slen; |
| 1134 |
u_int skip = 0; |
1111 |
u_int skip = 0; |
| 1135 |
int ret = -1; |
1112 |
int sign_ok = -1, have_sig = 1; |
| 1136 |
int have_sig = 1; |
1113 |
Key *private; |
|
|
1114 |
char *passphrase; |
| 1137 |
|
1115 |
|
| 1138 |
debug3("sign_and_send_pubkey"); |
1116 |
debug3("sign_and_send_pubkey"); |
| 1139 |
|
1117 |
|
|
Lines 1167-1175
sign_and_send_pubkey(Authctxt *authctxt,
Link Here
|
| 1167 |
buffer_put_string(&b, blob, bloblen); |
1145 |
buffer_put_string(&b, blob, bloblen); |
| 1168 |
|
1146 |
|
| 1169 |
/* generate signature */ |
1147 |
/* generate signature */ |
| 1170 |
ret = identity_sign(id, &signature, &slen, |
1148 |
if (id->ac) { |
| 1171 |
buffer_ptr(&b), buffer_len(&b)); |
1149 |
/* the agent supports this key */ |
| 1172 |
if (ret == -1) { |
1150 |
sign_ok = ssh_agent_sign(id->ac, id->key, &signature, &slen, |
|
|
1151 |
buffer_ptr(&b), buffer_len(&b)); |
| 1152 |
} else if (id->isprivate || (id->key->flags & KEY_FLAG_EXT)) { |
| 1153 |
/* |
| 1154 |
* we have already loaded the private key or the private key is |
| 1155 |
* stored in external hardware |
| 1156 |
*/ |
| 1157 |
sign_ok = key_sign(id->key, &signature, &slen, buffer_ptr(&b), |
| 1158 |
buffer_len(&b)); |
| 1159 |
} else { |
| 1160 |
/* load the private key from the file */ |
| 1161 |
private = load_identity_file(id, &passphrase); |
| 1162 |
if (private == NULL) |
| 1163 |
sign_ok = -1; |
| 1164 |
else { |
| 1165 |
sign_ok = key_sign(private, &signature, &slen, |
| 1166 |
buffer_ptr(&b), buffer_len(&b)); |
| 1167 |
|
| 1168 |
key_free(private); |
| 1169 |
|
| 1170 |
add_keys_to_agent(authctxt, passphrase); |
| 1171 |
} |
| 1172 |
} |
| 1173 |
|
| 1174 |
if (sign_ok == -1) { |
| 1173 |
xfree(blob); |
1175 |
xfree(blob); |
| 1174 |
buffer_free(&b); |
1176 |
buffer_free(&b); |
| 1175 |
return 0; |
1177 |
return 0; |
|
Lines 1240-1277
send_pubkey_test(Authctxt *authctxt, Ide
Link Here
|
| 1240 |
} |
1242 |
} |
| 1241 |
|
1243 |
|
| 1242 |
static Key * |
1244 |
static Key * |
| 1243 |
load_identity_file(char *filename) |
1245 |
load_identity_file(Identity *id, char **passphrase) |
| 1244 |
{ |
1246 |
{ |
| 1245 |
Key *private; |
1247 |
Key *private; |
| 1246 |
char prompt[300], *passphrase; |
1248 |
char prompt[300]; |
| 1247 |
int perm_ok = 0, quit, i; |
1249 |
int perm_ok = 0, quit, i; |
| 1248 |
struct stat st; |
1250 |
struct stat st; |
| 1249 |
|
1251 |
|
| 1250 |
if (stat(filename, &st) < 0) { |
1252 |
if (stat(id->filename, &st) < 0) { |
| 1251 |
debug3("no such identity: %s", filename); |
1253 |
debug3("no such identity: %s", id->filename); |
| 1252 |
return NULL; |
1254 |
return NULL; |
| 1253 |
} |
1255 |
} |
| 1254 |
private = key_load_private_type(KEY_UNSPEC, filename, "", NULL, &perm_ok); |
1256 |
*passphrase = NULL; |
|
|
1257 |
private = key_load_private_type(KEY_UNSPEC, id->filename, "", |
| 1258 |
&id->comment, &perm_ok); |
| 1255 |
if (!perm_ok) |
1259 |
if (!perm_ok) |
| 1256 |
return NULL; |
1260 |
return NULL; |
| 1257 |
if (private == NULL) { |
1261 |
if (private == NULL) { |
| 1258 |
if (options.batch_mode) |
1262 |
if (options.batch_mode) |
| 1259 |
return NULL; |
1263 |
return NULL; |
| 1260 |
snprintf(prompt, sizeof prompt, |
1264 |
snprintf(prompt, sizeof prompt, |
| 1261 |
"Enter passphrase for key '%.100s': ", filename); |
1265 |
"Enter passphrase for key '%.100s': ", id->filename); |
| 1262 |
for (i = 0; i < options.number_of_password_prompts; i++) { |
1266 |
for (i = 0; i < options.number_of_password_prompts; i++) { |
| 1263 |
passphrase = read_passphrase(prompt, 0); |
1267 |
*passphrase = read_passphrase(prompt, 0); |
| 1264 |
if (strcmp(passphrase, "") != 0) { |
1268 |
if (strcmp(*passphrase, "") != 0) { |
| 1265 |
private = key_load_private_type(KEY_UNSPEC, |
1269 |
private = key_load_private_type(KEY_UNSPEC, |
| 1266 |
filename, passphrase, NULL, NULL); |
1270 |
id->filename, *passphrase, &id->comment, |
|
|
1271 |
NULL); |
| 1267 |
quit = 0; |
1272 |
quit = 0; |
| 1268 |
} else { |
1273 |
} else { |
| 1269 |
debug2("no passphrase given, try next key"); |
1274 |
debug2("no passphrase given, try next key"); |
| 1270 |
quit = 1; |
1275 |
quit = 1; |
| 1271 |
} |
1276 |
} |
| 1272 |
memset(passphrase, 0, strlen(passphrase)); |
1277 |
if (private != NULL) |
| 1273 |
xfree(passphrase); |
1278 |
break; |
| 1274 |
if (private != NULL || quit) |
1279 |
memset(*passphrase, 0, strlen(*passphrase)); |
|
|
1280 |
xfree(*passphrase); |
| 1281 |
*passphrase = NULL; |
| 1282 |
if (quit) |
| 1275 |
break; |
1283 |
break; |
| 1276 |
debug2("bad passphrase given, try again..."); |
1284 |
debug2("bad passphrase given, try again..."); |
| 1277 |
} |
1285 |
} |
|
Lines 1293-1299
pubkey_prepare(Authctxt *authctxt)
Link Here
|
| 1293 |
Key *key; |
1301 |
Key *key; |
| 1294 |
AuthenticationConnection *ac; |
1302 |
AuthenticationConnection *ac; |
| 1295 |
char *comment; |
1303 |
char *comment; |
| 1296 |
int i, found; |
1304 |
int i, found, protocol; |
| 1297 |
|
1305 |
|
| 1298 |
TAILQ_INIT(&agent); /* keys from the agent */ |
1306 |
TAILQ_INIT(&agent); /* keys from the agent */ |
| 1299 |
TAILQ_INIT(&files); /* keys from the config file */ |
1307 |
TAILQ_INIT(&files); /* keys from the config file */ |
|
Lines 1303-1310
pubkey_prepare(Authctxt *authctxt)
Link Here
|
| 1303 |
/* list of keys stored in the filesystem */ |
1311 |
/* list of keys stored in the filesystem */ |
| 1304 |
for (i = 0; i < options.num_identity_files; i++) { |
1312 |
for (i = 0; i < options.num_identity_files; i++) { |
| 1305 |
key = options.identity_keys[i]; |
1313 |
key = options.identity_keys[i]; |
| 1306 |
if (key && key->type == KEY_RSA1) |
|
|
| 1307 |
continue; |
| 1308 |
options.identity_keys[i] = NULL; |
1314 |
options.identity_keys[i] = NULL; |
| 1309 |
id = xcalloc(1, sizeof(*id)); |
1315 |
id = xcalloc(1, sizeof(*id)); |
| 1310 |
id->key = key; |
1316 |
id->key = key; |
|
Lines 1313-1321
pubkey_prepare(Authctxt *authctxt)
Link Here
|
| 1313 |
} |
1319 |
} |
| 1314 |
/* list of keys supported by the agent */ |
1320 |
/* list of keys supported by the agent */ |
| 1315 |
if ((ac = ssh_get_authentication_connection())) { |
1321 |
if ((ac = ssh_get_authentication_connection())) { |
| 1316 |
for (key = ssh_get_first_identity(ac, &comment, 2); |
1322 |
for (key = ssh_get_first_identity(ac, &comment, protocol = 2); |
| 1317 |
key != NULL; |
1323 |
key != NULL || protocol == 2; |
| 1318 |
key = ssh_get_next_identity(ac, &comment, 2)) { |
1324 |
key = ssh_get_next_identity(ac, &comment, protocol)) { |
|
|
1325 |
if (key == NULL && options.add_keys_to_agent != 0) { |
| 1326 |
protocol = 1; |
| 1327 |
key = ssh_get_first_identity(ac, &comment, protocol); |
| 1328 |
} |
| 1329 |
if (key == NULL) |
| 1330 |
break; |
| 1319 |
found = 0; |
1331 |
found = 0; |
| 1320 |
TAILQ_FOREACH(id, &files, next) { |
1332 |
TAILQ_FOREACH(id, &files, next) { |
| 1321 |
/* agent keys from the config file are preferred */ |
1333 |
/* agent keys from the config file are preferred */ |
|
Lines 1368-1382
pubkey_cleanup(Authctxt *authctxt)
Link Here
|
| 1368 |
key_free(id->key); |
1380 |
key_free(id->key); |
| 1369 |
if (id->filename) |
1381 |
if (id->filename) |
| 1370 |
xfree(id->filename); |
1382 |
xfree(id->filename); |
|
|
1383 |
if (id->comment) |
| 1384 |
xfree(id->comment); |
| 1371 |
xfree(id); |
1385 |
xfree(id); |
| 1372 |
} |
1386 |
} |
| 1373 |
} |
1387 |
} |
| 1374 |
|
1388 |
|
|
|
1389 |
static void |
| 1390 |
add_keys_to_agent(Authctxt *authctxt, char *passphrase) |
| 1391 |
{ |
| 1392 |
Identity *id; |
| 1393 |
Key *private; |
| 1394 |
int perm_ok; |
| 1395 |
struct stat st; |
| 1396 |
|
| 1397 |
if (options.add_keys_to_agent == 0) |
| 1398 |
goto done; |
| 1399 |
|
| 1400 |
if (authctxt->agent == NULL) { |
| 1401 |
debug3("no connection to agent, not adding keys"); |
| 1402 |
goto done; |
| 1403 |
} |
| 1404 |
|
| 1405 |
TAILQ_FOREACH(id, &authctxt->keys, next) { |
| 1406 |
if (id->ac) { |
| 1407 |
debug3("key already in agent: %s", id->filename); |
| 1408 |
continue; |
| 1409 |
} |
| 1410 |
|
| 1411 |
if (id->key && id->isprivate) { |
| 1412 |
debug3("using private key loaded previously"); |
| 1413 |
private = id->key; |
| 1414 |
} else { |
| 1415 |
/* Try loading key */ |
| 1416 |
if (stat(id->filename, &st) < 0) { |
| 1417 |
debug3("no such identity to add to agent: %s", |
| 1418 |
id->filename); |
| 1419 |
continue; |
| 1420 |
} |
| 1421 |
private = key_load_private(id->filename, "", |
| 1422 |
&id->comment); |
| 1423 |
if (private == NULL && passphrase != NULL) |
| 1424 |
private = key_load_private(id->filename, |
| 1425 |
passphrase, &id->comment); |
| 1426 |
if (private == NULL) { |
| 1427 |
debug3("bad passphrase for identity: %s", id->filename); |
| 1428 |
continue; |
| 1429 |
} |
| 1430 |
} |
| 1431 |
|
| 1432 |
if (options.add_keys_to_agent == 2 && |
| 1433 |
!ask_permission("Add key %s (%s) to agent?", id->filename, |
| 1434 |
id->comment)) { |
| 1435 |
debug3("user did not confirm adding this key"); |
| 1436 |
key_free(private); |
| 1437 |
continue; |
| 1438 |
} |
| 1439 |
|
| 1440 |
if (ssh_add_identity_constrained(authctxt->agent, private, |
| 1441 |
id->comment, 0, options.add_keys_to_agent == 3)) |
| 1442 |
debug("Identity added to agent: %s (%s)", |
| 1443 |
id->filename, id->comment); |
| 1444 |
else |
| 1445 |
debug("Could not add identity: %s", id->filename); |
| 1446 |
|
| 1447 |
if (!id->isprivate || private != id->key) |
| 1448 |
key_free(private); |
| 1449 |
} |
| 1450 |
|
| 1451 |
done: |
| 1452 |
if (passphrase != NULL) { |
| 1453 |
memset(passphrase, 0, strlen(passphrase)); |
| 1454 |
xfree(passphrase); |
| 1455 |
} |
| 1456 |
} |
| 1457 |
|
| 1375 |
int |
1458 |
int |
| 1376 |
userauth_pubkey(Authctxt *authctxt) |
1459 |
userauth_pubkey(Authctxt *authctxt) |
| 1377 |
{ |
1460 |
{ |
| 1378 |
Identity *id; |
1461 |
Identity *id; |
| 1379 |
int sent = 0; |
1462 |
int sent = 0; |
|
|
1463 |
char *passphrase; |
| 1380 |
|
1464 |
|
| 1381 |
while ((id = TAILQ_FIRST(&authctxt->keys))) { |
1465 |
while ((id = TAILQ_FIRST(&authctxt->keys))) { |
| 1382 |
if (id->tried++) |
1466 |
if (id->tried++) |
|
Lines 1394-1402
userauth_pubkey(Authctxt *authctxt)
Link Here
|
| 1394 |
sent = send_pubkey_test(authctxt, id); |
1478 |
sent = send_pubkey_test(authctxt, id); |
| 1395 |
} else if (id->key == NULL) { |
1479 |
} else if (id->key == NULL) { |
| 1396 |
debug("Trying private key: %s", id->filename); |
1480 |
debug("Trying private key: %s", id->filename); |
| 1397 |
id->key = load_identity_file(id->filename); |
1481 |
id->key = load_identity_file(id, &passphrase); |
| 1398 |
if (id->key != NULL) { |
1482 |
if (id->key != NULL) { |
| 1399 |
id->isprivate = 1; |
1483 |
id->isprivate = 1; |
|
|
1484 |
add_keys_to_agent(authctxt, passphrase); |
| 1400 |
sent = sign_and_send_pubkey(authctxt, id); |
1485 |
sent = sign_and_send_pubkey(authctxt, id); |
| 1401 |
key_free(id->key); |
1486 |
key_free(id->key); |
| 1402 |
id->key = NULL; |
1487 |
id->key = NULL; |