version 1.62, 2018/02/23 15:58:38 |
version 1.63, 2018/03/02 02:08:03 |
|
|
return retval; |
return retval; |
} |
} |
|
|
|
static int |
|
peek_type_nid(const char *s, size_t l, int *nid) |
|
{ |
|
const struct keytype *kt; |
|
|
/* returns 0 ok, and < 0 error */ |
for (kt = keytypes; kt->type != -1; kt++) { |
|
if (kt->name == NULL || strlen(kt->name) != l) |
|
continue; |
|
if (memcmp(s, kt->name, l) == 0) { |
|
*nid = -1; |
|
if (kt->type == KEY_ECDSA || kt->type == KEY_ECDSA_CERT) |
|
*nid = kt->nid; |
|
return kt->type; |
|
} |
|
} |
|
return KEY_UNSPEC; |
|
} |
|
|
|
|
|
/* XXX this can now be made const char * */ |
int |
int |
sshkey_read(struct sshkey *ret, char **cpp) |
sshkey_read(struct sshkey *ret, char **cpp) |
{ |
{ |
struct sshkey *k; |
struct sshkey *k; |
int retval = SSH_ERR_INVALID_FORMAT; |
char *cp, *blobcopy; |
char *ep, *cp, *space; |
size_t space; |
int r, type, curve_nid = -1; |
int r, type, curve_nid = -1; |
struct sshbuf *blob; |
struct sshbuf *blob; |
|
|
if (ret == NULL) |
if (ret == NULL) |
return SSH_ERR_INVALID_ARGUMENT; |
return SSH_ERR_INVALID_ARGUMENT; |
|
|
cp = *cpp; |
|
|
|
switch (ret->type) { |
switch (ret->type) { |
case KEY_UNSPEC: |
case KEY_UNSPEC: |
case KEY_RSA: |
case KEY_RSA: |
|
|
case KEY_XMSS: |
case KEY_XMSS: |
case KEY_XMSS_CERT: |
case KEY_XMSS_CERT: |
#endif /* WITH_XMSS */ |
#endif /* WITH_XMSS */ |
space = strchr(cp, ' '); |
break; /* ok */ |
if (space == NULL) |
default: |
return SSH_ERR_INVALID_FORMAT; |
return SSH_ERR_INVALID_ARGUMENT; |
*space = '\0'; |
} |
type = sshkey_type_from_name(cp); |
|
if (sshkey_type_plain(type) == KEY_ECDSA && |
/* Decode type */ |
(curve_nid = sshkey_ecdsa_nid_from_name(cp)) == -1) |
cp = *cpp; |
return SSH_ERR_EC_CURVE_INVALID; |
space = strcspn(cp, " \t"); |
*space = ' '; |
if (space == strlen(cp)) |
if (type == KEY_UNSPEC) |
return SSH_ERR_INVALID_FORMAT; |
return SSH_ERR_INVALID_FORMAT; |
if ((type = peek_type_nid(cp, space, &curve_nid)) == KEY_UNSPEC) |
cp = space+1; |
return SSH_ERR_INVALID_FORMAT; |
if (*cp == '\0') |
|
return SSH_ERR_INVALID_FORMAT; |
/* skip whitespace */ |
if (ret->type != KEY_UNSPEC && ret->type != type) |
for (cp += space; *cp == ' ' || *cp == '\t'; cp++) |
return SSH_ERR_KEY_TYPE_MISMATCH; |
; |
if ((blob = sshbuf_new()) == NULL) |
if (*cp == '\0') |
return SSH_ERR_ALLOC_FAIL; |
return SSH_ERR_INVALID_FORMAT; |
/* trim comment */ |
if (ret->type != KEY_UNSPEC && ret->type != type) |
space = strchr(cp, ' '); |
return SSH_ERR_KEY_TYPE_MISMATCH; |
if (space) { |
if ((blob = sshbuf_new()) == NULL) |
/* advance 'space': skip whitespace */ |
return SSH_ERR_ALLOC_FAIL; |
*space++ = '\0'; |
|
while (*space == ' ' || *space == '\t') |
/* find end of keyblob and decode */ |
space++; |
space = strcspn(cp, " \t"); |
ep = space; |
if ((blobcopy = strndup(cp, space)) == NULL) { |
} else |
|
ep = cp + strlen(cp); |
|
if ((r = sshbuf_b64tod(blob, cp)) != 0) { |
|
sshbuf_free(blob); |
|
return r; |
|
} |
|
if ((r = sshkey_from_blob(sshbuf_ptr(blob), |
|
sshbuf_len(blob), &k)) != 0) { |
|
sshbuf_free(blob); |
|
return r; |
|
} |
|
sshbuf_free(blob); |
sshbuf_free(blob); |
if (k->type != type) { |
return SSH_ERR_ALLOC_FAIL; |
|
} |
|
if ((r = sshbuf_b64tod(blob, blobcopy)) != 0) { |
|
free(blobcopy); |
|
sshbuf_free(blob); |
|
return r; |
|
} |
|
free(blobcopy); |
|
if ((r = sshkey_fromb(blob, &k)) != 0) { |
|
sshbuf_free(blob); |
|
return r; |
|
} |
|
sshbuf_free(blob); |
|
|
|
/* skip whitespace and leave cp at start of comment */ |
|
for (cp += space; *cp == ' ' || *cp == '\t'; cp++) |
|
; |
|
|
|
/* ensure type of blob matches type at start of line */ |
|
if (k->type != type) { |
|
sshkey_free(k); |
|
return SSH_ERR_KEY_TYPE_MISMATCH; |
|
} |
|
if (sshkey_type_plain(type) == KEY_ECDSA && curve_nid != k->ecdsa_nid) { |
|
sshkey_free(k); |
|
return SSH_ERR_EC_CURVE_MISMATCH; |
|
} |
|
|
|
/* Fill in ret from parsed key */ |
|
ret->type = type; |
|
if (sshkey_is_cert(ret)) { |
|
if (!sshkey_is_cert(k)) { |
sshkey_free(k); |
sshkey_free(k); |
return SSH_ERR_KEY_TYPE_MISMATCH; |
return SSH_ERR_EXPECTED_CERT; |
} |
} |
if (sshkey_type_plain(type) == KEY_ECDSA && |
if (ret->cert != NULL) |
curve_nid != k->ecdsa_nid) { |
cert_free(ret->cert); |
sshkey_free(k); |
ret->cert = k->cert; |
return SSH_ERR_EC_CURVE_MISMATCH; |
k->cert = NULL; |
} |
} |
ret->type = type; |
switch (sshkey_type_plain(ret->type)) { |
if (sshkey_is_cert(ret)) { |
|
if (!sshkey_is_cert(k)) { |
|
sshkey_free(k); |
|
return SSH_ERR_EXPECTED_CERT; |
|
} |
|
if (ret->cert != NULL) |
|
cert_free(ret->cert); |
|
ret->cert = k->cert; |
|
k->cert = NULL; |
|
} |
|
switch (sshkey_type_plain(ret->type)) { |
|
#ifdef WITH_OPENSSL |
#ifdef WITH_OPENSSL |
case KEY_RSA: |
case KEY_RSA: |
RSA_free(ret->rsa); |
RSA_free(ret->rsa); |
ret->rsa = k->rsa; |
ret->rsa = k->rsa; |
k->rsa = NULL; |
k->rsa = NULL; |
#ifdef DEBUG_PK |
#ifdef DEBUG_PK |
RSA_print_fp(stderr, ret->rsa, 8); |
RSA_print_fp(stderr, ret->rsa, 8); |
#endif |
#endif |
break; |
break; |
case KEY_DSA: |
case KEY_DSA: |
DSA_free(ret->dsa); |
DSA_free(ret->dsa); |
ret->dsa = k->dsa; |
ret->dsa = k->dsa; |
k->dsa = NULL; |
k->dsa = NULL; |
#ifdef DEBUG_PK |
#ifdef DEBUG_PK |
DSA_print_fp(stderr, ret->dsa, 8); |
DSA_print_fp(stderr, ret->dsa, 8); |
#endif |
#endif |
break; |
break; |
case KEY_ECDSA: |
case KEY_ECDSA: |
EC_KEY_free(ret->ecdsa); |
EC_KEY_free(ret->ecdsa); |
ret->ecdsa = k->ecdsa; |
ret->ecdsa = k->ecdsa; |
ret->ecdsa_nid = k->ecdsa_nid; |
ret->ecdsa_nid = k->ecdsa_nid; |
k->ecdsa = NULL; |
k->ecdsa = NULL; |
k->ecdsa_nid = -1; |
k->ecdsa_nid = -1; |
#ifdef DEBUG_PK |
#ifdef DEBUG_PK |
sshkey_dump_ec_key(ret->ecdsa); |
sshkey_dump_ec_key(ret->ecdsa); |
#endif |
#endif |
break; |
break; |
#endif /* WITH_OPENSSL */ |
#endif /* WITH_OPENSSL */ |
case KEY_ED25519: |
case KEY_ED25519: |
freezero(ret->ed25519_pk, ED25519_PK_SZ); |
freezero(ret->ed25519_pk, ED25519_PK_SZ); |
ret->ed25519_pk = k->ed25519_pk; |
ret->ed25519_pk = k->ed25519_pk; |
k->ed25519_pk = NULL; |
k->ed25519_pk = NULL; |
#ifdef DEBUG_PK |
#ifdef DEBUG_PK |
/* XXX */ |
/* XXX */ |
#endif |
#endif |
break; |
break; |
#ifdef WITH_XMSS |
#ifdef WITH_XMSS |
case KEY_XMSS: |
case KEY_XMSS: |
free(ret->xmss_pk); |
free(ret->xmss_pk); |
ret->xmss_pk = k->xmss_pk; |
ret->xmss_pk = k->xmss_pk; |
k->xmss_pk = NULL; |
k->xmss_pk = NULL; |
free(ret->xmss_state); |
free(ret->xmss_state); |
ret->xmss_state = k->xmss_state; |
ret->xmss_state = k->xmss_state; |
k->xmss_state = NULL; |
k->xmss_state = NULL; |
free(ret->xmss_name); |
free(ret->xmss_name); |
ret->xmss_name = k->xmss_name; |
ret->xmss_name = k->xmss_name; |
k->xmss_name = NULL; |
k->xmss_name = NULL; |
free(ret->xmss_filename); |
free(ret->xmss_filename); |
ret->xmss_filename = k->xmss_filename; |
ret->xmss_filename = k->xmss_filename; |
k->xmss_filename = NULL; |
k->xmss_filename = NULL; |
#ifdef DEBUG_PK |
#ifdef DEBUG_PK |
/* XXX */ |
/* XXX */ |
#endif |
#endif |
break; |
|
#endif /* WITH_XMSS */ |
|
} |
|
*cpp = ep; |
|
retval = 0; |
|
/*XXXX*/ |
|
sshkey_free(k); |
|
if (retval != 0) |
|
break; |
|
break; |
break; |
|
#endif /* WITH_XMSS */ |
default: |
default: |
return SSH_ERR_INVALID_ARGUMENT; |
sshkey_free(k); |
|
return SSH_ERR_INTERNAL_ERROR; |
} |
} |
return retval; |
sshkey_free(k); |
|
|
|
/* success */ |
|
*cpp = cp; |
|
return 0; |
} |
} |
|
|
int |
int |