diff options
author | djm@openbsd.org <djm@openbsd.org> | 2018-03-02 02:08:03 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2018-03-02 14:39:16 +1100 |
commit | 94b4e2d29afaaaef89a95289b16c18bf5627f7cd (patch) | |
tree | 1eebba00756deab4faa7707d2fc7eb1f075f41df /sshkey.c | |
parent | 5886b92968b360623491699247caddfb77a74d80 (diff) |
upstream: refactor sshkey_read() to make it a little more, err,
readable. ok markus
OpenBSD-Commit-ID: 2e9247b5762fdac3b6335dc606d3822121714c28
Diffstat (limited to 'sshkey.c')
-rw-r--r-- | sshkey.c | 248 |
1 files changed, 135 insertions, 113 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.62 2018/02/23 15:58:38 markus Exp $ */ | 1 | /* $OpenBSD: sshkey.c,v 1.63 2018/03/02 02:08:03 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | 4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. |
@@ -1215,22 +1215,37 @@ sshkey_fingerprint(const struct sshkey *k, int dgst_alg, | |||
1215 | return retval; | 1215 | return retval; |
1216 | } | 1216 | } |
1217 | 1217 | ||
1218 | static int | ||
1219 | peek_type_nid(const char *s, size_t l, int *nid) | ||
1220 | { | ||
1221 | const struct keytype *kt; | ||
1222 | |||
1223 | for (kt = keytypes; kt->type != -1; kt++) { | ||
1224 | if (kt->name == NULL || strlen(kt->name) != l) | ||
1225 | continue; | ||
1226 | if (memcmp(s, kt->name, l) == 0) { | ||
1227 | *nid = -1; | ||
1228 | if (kt->type == KEY_ECDSA || kt->type == KEY_ECDSA_CERT) | ||
1229 | *nid = kt->nid; | ||
1230 | return kt->type; | ||
1231 | } | ||
1232 | } | ||
1233 | return KEY_UNSPEC; | ||
1234 | } | ||
1218 | 1235 | ||
1219 | /* returns 0 ok, and < 0 error */ | 1236 | /* XXX this can now be made const char * */ |
1220 | int | 1237 | int |
1221 | sshkey_read(struct sshkey *ret, char **cpp) | 1238 | sshkey_read(struct sshkey *ret, char **cpp) |
1222 | { | 1239 | { |
1223 | struct sshkey *k; | 1240 | struct sshkey *k; |
1224 | int retval = SSH_ERR_INVALID_FORMAT; | 1241 | char *cp, *blobcopy; |
1225 | char *ep, *cp, *space; | 1242 | size_t space; |
1226 | int r, type, curve_nid = -1; | 1243 | int r, type, curve_nid = -1; |
1227 | struct sshbuf *blob; | 1244 | struct sshbuf *blob; |
1228 | 1245 | ||
1229 | if (ret == NULL) | 1246 | if (ret == NULL) |
1230 | return SSH_ERR_INVALID_ARGUMENT; | 1247 | return SSH_ERR_INVALID_ARGUMENT; |
1231 | 1248 | ||
1232 | cp = *cpp; | ||
1233 | |||
1234 | switch (ret->type) { | 1249 | switch (ret->type) { |
1235 | case KEY_UNSPEC: | 1250 | case KEY_UNSPEC: |
1236 | case KEY_RSA: | 1251 | case KEY_RSA: |
@@ -1245,136 +1260,143 @@ sshkey_read(struct sshkey *ret, char **cpp) | |||
1245 | case KEY_XMSS: | 1260 | case KEY_XMSS: |
1246 | case KEY_XMSS_CERT: | 1261 | case KEY_XMSS_CERT: |
1247 | #endif /* WITH_XMSS */ | 1262 | #endif /* WITH_XMSS */ |
1248 | space = strchr(cp, ' '); | 1263 | break; /* ok */ |
1249 | if (space == NULL) | 1264 | default: |
1250 | return SSH_ERR_INVALID_FORMAT; | 1265 | return SSH_ERR_INVALID_ARGUMENT; |
1251 | *space = '\0'; | 1266 | } |
1252 | type = sshkey_type_from_name(cp); | 1267 | |
1253 | if (sshkey_type_plain(type) == KEY_ECDSA && | 1268 | /* Decode type */ |
1254 | (curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1) | 1269 | cp = *cpp; |
1255 | return SSH_ERR_EC_CURVE_INVALID; | 1270 | space = strcspn(cp, " \t"); |
1256 | *space = ' '; | 1271 | if (space == strlen(cp)) |
1257 | if (type == KEY_UNSPEC) | 1272 | return SSH_ERR_INVALID_FORMAT; |
1258 | return SSH_ERR_INVALID_FORMAT; | 1273 | if ((type = peek_type_nid(cp, space, &curve_nid)) == KEY_UNSPEC) |
1259 | cp = space+1; | 1274 | return SSH_ERR_INVALID_FORMAT; |
1260 | if (*cp == '\0') | 1275 | |
1261 | return SSH_ERR_INVALID_FORMAT; | 1276 | /* skip whitespace */ |
1262 | if (ret->type != KEY_UNSPEC && ret->type != type) | 1277 | for (cp += space; *cp == ' ' || *cp == '\t'; cp++) |
1263 | return SSH_ERR_KEY_TYPE_MISMATCH; | 1278 | ; |
1264 | if ((blob = sshbuf_new()) == NULL) | 1279 | if (*cp == '\0') |
1265 | return SSH_ERR_ALLOC_FAIL; | 1280 | return SSH_ERR_INVALID_FORMAT; |
1266 | /* trim comment */ | 1281 | if (ret->type != KEY_UNSPEC && ret->type != type) |
1267 | space = strchr(cp, ' '); | 1282 | return SSH_ERR_KEY_TYPE_MISMATCH; |
1268 | if (space) { | 1283 | if ((blob = sshbuf_new()) == NULL) |
1269 | /* advance 'space': skip whitespace */ | 1284 | return SSH_ERR_ALLOC_FAIL; |
1270 | *space++ = '\0'; | 1285 | |
1271 | while (*space == ' ' || *space == '\t') | 1286 | /* find end of keyblob and decode */ |
1272 | space++; | 1287 | space = strcspn(cp, " \t"); |
1273 | ep = space; | 1288 | if ((blobcopy = strndup(cp, space)) == NULL) { |
1274 | } else | ||
1275 | ep = cp + strlen(cp); | ||
1276 | if ((r = sshbuf_b64tod(blob, cp)) != 0) { | ||
1277 | sshbuf_free(blob); | ||
1278 | return r; | ||
1279 | } | ||
1280 | if ((r = sshkey_from_blob(sshbuf_ptr(blob), | ||
1281 | sshbuf_len(blob), &k)) != 0) { | ||
1282 | sshbuf_free(blob); | ||
1283 | return r; | ||
1284 | } | ||
1285 | sshbuf_free(blob); | 1289 | sshbuf_free(blob); |
1286 | if (k->type != type) { | 1290 | return SSH_ERR_ALLOC_FAIL; |
1287 | sshkey_free(k); | 1291 | } |
1288 | return SSH_ERR_KEY_TYPE_MISMATCH; | 1292 | if ((r = sshbuf_b64tod(blob, blobcopy)) != 0) { |
1289 | } | 1293 | free(blobcopy); |
1290 | if (sshkey_type_plain(type) == KEY_ECDSA && | 1294 | sshbuf_free(blob); |
1291 | curve_nid != k->ecdsa_nid) { | 1295 | return r; |
1296 | } | ||
1297 | free(blobcopy); | ||
1298 | if ((r = sshkey_fromb(blob, &k)) != 0) { | ||
1299 | sshbuf_free(blob); | ||
1300 | return r; | ||
1301 | } | ||
1302 | sshbuf_free(blob); | ||
1303 | |||
1304 | /* skip whitespace and leave cp at start of comment */ | ||
1305 | for (cp += space; *cp == ' ' || *cp == '\t'; cp++) | ||
1306 | ; | ||
1307 | |||
1308 | /* ensure type of blob matches type at start of line */ | ||
1309 | if (k->type != type) { | ||
1310 | sshkey_free(k); | ||
1311 | return SSH_ERR_KEY_TYPE_MISMATCH; | ||
1312 | } | ||
1313 | if (sshkey_type_plain(type) == KEY_ECDSA && curve_nid != k->ecdsa_nid) { | ||
1314 | sshkey_free(k); | ||
1315 | return SSH_ERR_EC_CURVE_MISMATCH; | ||
1316 | } | ||
1317 | |||
1318 | /* Fill in ret from parsed key */ | ||
1319 | ret->type = type; | ||
1320 | if (sshkey_is_cert(ret)) { | ||
1321 | if (!sshkey_is_cert(k)) { | ||
1292 | sshkey_free(k); | 1322 | sshkey_free(k); |
1293 | return SSH_ERR_EC_CURVE_MISMATCH; | 1323 | return SSH_ERR_EXPECTED_CERT; |
1294 | } | ||
1295 | ret->type = type; | ||
1296 | if (sshkey_is_cert(ret)) { | ||
1297 | if (!sshkey_is_cert(k)) { | ||
1298 | sshkey_free(k); | ||
1299 | return SSH_ERR_EXPECTED_CERT; | ||
1300 | } | ||
1301 | if (ret->cert != NULL) | ||
1302 | cert_free(ret->cert); | ||
1303 | ret->cert = k->cert; | ||
1304 | k->cert = NULL; | ||
1305 | } | 1324 | } |
1306 | switch (sshkey_type_plain(ret->type)) { | 1325 | if (ret->cert != NULL) |
1326 | cert_free(ret->cert); | ||
1327 | ret->cert = k->cert; | ||
1328 | k->cert = NULL; | ||
1329 | } | ||
1330 | switch (sshkey_type_plain(ret->type)) { | ||
1307 | #ifdef WITH_OPENSSL | 1331 | #ifdef WITH_OPENSSL |
1308 | case KEY_RSA: | 1332 | case KEY_RSA: |
1309 | RSA_free(ret->rsa); | 1333 | RSA_free(ret->rsa); |
1310 | ret->rsa = k->rsa; | 1334 | ret->rsa = k->rsa; |
1311 | k->rsa = NULL; | 1335 | k->rsa = NULL; |
1312 | #ifdef DEBUG_PK | 1336 | #ifdef DEBUG_PK |
1313 | RSA_print_fp(stderr, ret->rsa, 8); | 1337 | RSA_print_fp(stderr, ret->rsa, 8); |
1314 | #endif | 1338 | #endif |
1315 | break; | 1339 | break; |
1316 | case KEY_DSA: | 1340 | case KEY_DSA: |
1317 | DSA_free(ret->dsa); | 1341 | DSA_free(ret->dsa); |
1318 | ret->dsa = k->dsa; | 1342 | ret->dsa = k->dsa; |
1319 | k->dsa = NULL; | 1343 | k->dsa = NULL; |
1320 | #ifdef DEBUG_PK | 1344 | #ifdef DEBUG_PK |
1321 | DSA_print_fp(stderr, ret->dsa, 8); | 1345 | DSA_print_fp(stderr, ret->dsa, 8); |
1322 | #endif | 1346 | #endif |
1323 | break; | 1347 | break; |
1324 | # ifdef OPENSSL_HAS_ECC | 1348 | # ifdef OPENSSL_HAS_ECC |
1325 | case KEY_ECDSA: | 1349 | case KEY_ECDSA: |
1326 | EC_KEY_free(ret->ecdsa); | 1350 | EC_KEY_free(ret->ecdsa); |
1327 | ret->ecdsa = k->ecdsa; | 1351 | ret->ecdsa = k->ecdsa; |
1328 | ret->ecdsa_nid = k->ecdsa_nid; | 1352 | ret->ecdsa_nid = k->ecdsa_nid; |
1329 | k->ecdsa = NULL; | 1353 | k->ecdsa = NULL; |
1330 | k->ecdsa_nid = -1; | 1354 | k->ecdsa_nid = -1; |
1331 | #ifdef DEBUG_PK | 1355 | #ifdef DEBUG_PK |
1332 | sshkey_dump_ec_key(ret->ecdsa); | 1356 | sshkey_dump_ec_key(ret->ecdsa); |
1333 | #endif | 1357 | #endif |
1334 | break; | 1358 | break; |
1335 | # endif /* OPENSSL_HAS_ECC */ | 1359 | # endif /* OPENSSL_HAS_ECC */ |
1336 | #endif /* WITH_OPENSSL */ | 1360 | #endif /* WITH_OPENSSL */ |
1337 | case KEY_ED25519: | 1361 | case KEY_ED25519: |
1338 | freezero(ret->ed25519_pk, ED25519_PK_SZ); | 1362 | freezero(ret->ed25519_pk, ED25519_PK_SZ); |
1339 | ret->ed25519_pk = k->ed25519_pk; | 1363 | ret->ed25519_pk = k->ed25519_pk; |
1340 | k->ed25519_pk = NULL; | 1364 | k->ed25519_pk = NULL; |
1341 | #ifdef DEBUG_PK | 1365 | #ifdef DEBUG_PK |
1342 | /* XXX */ | 1366 | /* XXX */ |
1343 | #endif | 1367 | #endif |
1344 | break; | 1368 | break; |
1345 | #ifdef WITH_XMSS | 1369 | #ifdef WITH_XMSS |
1346 | case KEY_XMSS: | 1370 | case KEY_XMSS: |
1347 | free(ret->xmss_pk); | 1371 | free(ret->xmss_pk); |
1348 | ret->xmss_pk = k->xmss_pk; | 1372 | ret->xmss_pk = k->xmss_pk; |
1349 | k->xmss_pk = NULL; | 1373 | k->xmss_pk = NULL; |
1350 | free(ret->xmss_state); | 1374 | free(ret->xmss_state); |
1351 | ret->xmss_state = k->xmss_state; | 1375 | ret->xmss_state = k->xmss_state; |
1352 | k->xmss_state = NULL; | 1376 | k->xmss_state = NULL; |
1353 | free(ret->xmss_name); | 1377 | free(ret->xmss_name); |
1354 | ret->xmss_name = k->xmss_name; | 1378 | ret->xmss_name = k->xmss_name; |
1355 | k->xmss_name = NULL; | 1379 | k->xmss_name = NULL; |
1356 | free(ret->xmss_filename); | 1380 | free(ret->xmss_filename); |
1357 | ret->xmss_filename = k->xmss_filename; | 1381 | ret->xmss_filename = k->xmss_filename; |
1358 | k->xmss_filename = NULL; | 1382 | k->xmss_filename = NULL; |
1359 | #ifdef DEBUG_PK | 1383 | #ifdef DEBUG_PK |
1360 | /* XXX */ | 1384 | /* XXX */ |
1361 | #endif | 1385 | #endif |
1362 | break; | ||
1363 | #endif /* WITH_XMSS */ | ||
1364 | } | ||
1365 | *cpp = ep; | ||
1366 | retval = 0; | ||
1367 | /*XXXX*/ | ||
1368 | sshkey_free(k); | ||
1369 | if (retval != 0) | ||
1370 | break; | ||
1371 | break; | 1386 | break; |
1387 | #endif /* WITH_XMSS */ | ||
1372 | default: | 1388 | default: |
1373 | return SSH_ERR_INVALID_ARGUMENT; | 1389 | sshkey_free(k); |
1390 | return SSH_ERR_INTERNAL_ERROR; | ||
1374 | } | 1391 | } |
1375 | return retval; | 1392 | sshkey_free(k); |
1393 | |||
1394 | /* success */ | ||
1395 | *cpp = cp; | ||
1396 | return 0; | ||
1376 | } | 1397 | } |
1377 | 1398 | ||
1399 | |||
1378 | int | 1400 | int |
1379 | sshkey_to_base64(const struct sshkey *key, char **b64p) | 1401 | sshkey_to_base64(const struct sshkey *key, char **b64p) |
1380 | { | 1402 | { |