version 1.66, 2018/07/03 13:20:25 |
version 1.67, 2018/09/12 01:31:30 |
|
|
struct sshbuf *buf, enum sshkey_serialize_rep); |
struct sshbuf *buf, enum sshkey_serialize_rep); |
static int sshkey_from_blob_internal(struct sshbuf *buf, |
static int sshkey_from_blob_internal(struct sshbuf *buf, |
struct sshkey **keyp, int allow_cert); |
struct sshkey **keyp, int allow_cert); |
|
static int get_sigtype(const u_char *sig, size_t siglen, char **sigtypep); |
|
|
/* Supported key types */ |
/* Supported key types */ |
struct keytype { |
struct keytype { |
|
|
free(cert->principals[i]); |
free(cert->principals[i]); |
free(cert->principals); |
free(cert->principals); |
sshkey_free(cert->signature_key); |
sshkey_free(cert->signature_key); |
|
free(cert->signature_type); |
freezero(cert, sizeof(*cert)); |
freezero(cert, sizeof(*cert)); |
} |
} |
|
|
|
|
cert->key_id = NULL; |
cert->key_id = NULL; |
cert->principals = NULL; |
cert->principals = NULL; |
cert->signature_key = NULL; |
cert->signature_key = NULL; |
|
cert->signature_type = NULL; |
return cert; |
return cert; |
} |
} |
|
|
|
|
u_int i; |
u_int i; |
const struct sshkey_cert *from; |
const struct sshkey_cert *from; |
struct sshkey_cert *to; |
struct sshkey_cert *to; |
int ret = SSH_ERR_INTERNAL_ERROR; |
int r = SSH_ERR_INTERNAL_ERROR; |
|
|
if (to_key->cert != NULL) { |
if (to_key == NULL || (from = from_key->cert) == NULL) |
cert_free(to_key->cert); |
|
to_key->cert = NULL; |
|
} |
|
|
|
if ((from = from_key->cert) == NULL) |
|
return SSH_ERR_INVALID_ARGUMENT; |
return SSH_ERR_INVALID_ARGUMENT; |
|
|
if ((to = to_key->cert = cert_new()) == NULL) |
if ((to = cert_new()) == NULL) |
return SSH_ERR_ALLOC_FAIL; |
return SSH_ERR_ALLOC_FAIL; |
|
|
if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 || |
if ((r = sshbuf_putb(to->certblob, from->certblob)) != 0 || |
(ret = sshbuf_putb(to->critical, from->critical)) != 0 || |
(r = sshbuf_putb(to->critical, from->critical)) != 0 || |
(ret = sshbuf_putb(to->extensions, from->extensions)) != 0) |
(r = sshbuf_putb(to->extensions, from->extensions)) != 0) |
return ret; |
goto out; |
|
|
to->serial = from->serial; |
to->serial = from->serial; |
to->type = from->type; |
to->type = from->type; |
if (from->key_id == NULL) |
if (from->key_id == NULL) |
to->key_id = NULL; |
to->key_id = NULL; |
else if ((to->key_id = strdup(from->key_id)) == NULL) |
else if ((to->key_id = strdup(from->key_id)) == NULL) { |
return SSH_ERR_ALLOC_FAIL; |
r = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
to->valid_after = from->valid_after; |
to->valid_after = from->valid_after; |
to->valid_before = from->valid_before; |
to->valid_before = from->valid_before; |
if (from->signature_key == NULL) |
if (from->signature_key == NULL) |
to->signature_key = NULL; |
to->signature_key = NULL; |
else if ((ret = sshkey_from_private(from->signature_key, |
else if ((r = sshkey_from_private(from->signature_key, |
&to->signature_key)) != 0) |
&to->signature_key)) != 0) |
return ret; |
goto out; |
|
if (from->signature_type != NULL && |
if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) |
(to->signature_type = strdup(from->signature_type)) == NULL) { |
return SSH_ERR_INVALID_ARGUMENT; |
r = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
|
if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS) { |
|
r = SSH_ERR_INVALID_ARGUMENT; |
|
goto out; |
|
} |
if (from->nprincipals > 0) { |
if (from->nprincipals > 0) { |
if ((to->principals = calloc(from->nprincipals, |
if ((to->principals = calloc(from->nprincipals, |
sizeof(*to->principals))) == NULL) |
sizeof(*to->principals))) == NULL) { |
return SSH_ERR_ALLOC_FAIL; |
r = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
|
} |
for (i = 0; i < from->nprincipals; i++) { |
for (i = 0; i < from->nprincipals; i++) { |
to->principals[i] = strdup(from->principals[i]); |
to->principals[i] = strdup(from->principals[i]); |
if (to->principals[i] == NULL) { |
if (to->principals[i] == NULL) { |
to->nprincipals = i; |
to->nprincipals = i; |
return SSH_ERR_ALLOC_FAIL; |
r = SSH_ERR_ALLOC_FAIL; |
|
goto out; |
} |
} |
} |
} |
} |
} |
to->nprincipals = from->nprincipals; |
to->nprincipals = from->nprincipals; |
return 0; |
|
|
/* success */ |
|
cert_free(to_key->cert); |
|
to_key->cert = to; |
|
to = NULL; |
|
r = 0; |
|
out: |
|
cert_free(to); |
|
return r; |
} |
} |
|
|
int |
int |
|
|
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, |
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen, |
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0) |
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0) |
goto out; |
goto out; |
|
if ((ret = get_sigtype(sig, slen, &key->cert->signature_type)) != 0) |
|
goto out; |
|
|
/* Success */ |
/* Success */ |
ret = 0; |
ret = 0; |
|
|
u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; |
u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; |
size_t i, ca_len, sig_len; |
size_t i, ca_len, sig_len; |
int ret = SSH_ERR_INTERNAL_ERROR; |
int ret = SSH_ERR_INTERNAL_ERROR; |
struct sshbuf *cert; |
struct sshbuf *cert = NULL; |
|
char *sigtype = NULL; |
|
|
if (k == NULL || k->cert == NULL || |
if (k == NULL || k->cert == NULL || |
k->cert->certblob == NULL || ca == NULL) |
k->cert->certblob == NULL || ca == NULL) |
|
|
if (!sshkey_type_is_valid_ca(ca->type)) |
if (!sshkey_type_is_valid_ca(ca->type)) |
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
|
|
|
/* |
|
* If no alg specified as argument but a signature_type was set, |
|
* then prefer that. If both were specified, then they must match. |
|
*/ |
|
if (alg == NULL) |
|
alg = k->cert->signature_type; |
|
else if (k->cert->signature_type != NULL && |
|
strcmp(alg, k->cert->signature_type) != 0) |
|
return SSH_ERR_INVALID_ARGUMENT; |
|
|
if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) |
if ((ret = sshkey_to_blob(ca, &ca_blob, &ca_len)) != 0) |
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY; |
|
|
|
|
if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), |
if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), |
sshbuf_len(cert), alg, 0, signer_ctx)) != 0) |
sshbuf_len(cert), alg, 0, signer_ctx)) != 0) |
goto out; |
goto out; |
|
/* Check and update signature_type against what was actually used */ |
|
if ((ret = get_sigtype(sig_blob, sig_len, &sigtype)) != 0) |
|
goto out; |
|
if (alg != NULL && strcmp(alg, sigtype) != 0) { |
|
ret = SSH_ERR_SIGN_ALG_UNSUPPORTED; |
|
goto out; |
|
} |
|
if (k->cert->signature_type == NULL) { |
|
k->cert->signature_type = sigtype; |
|
sigtype = NULL; |
|
} |
/* Append signature and we are done */ |
/* Append signature and we are done */ |
if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) |
if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0) |
goto out; |
goto out; |
|
|
sshbuf_reset(cert); |
sshbuf_reset(cert); |
free(sig_blob); |
free(sig_blob); |
free(ca_blob); |
free(ca_blob); |
|
free(sigtype); |
sshbuf_free(principals); |
sshbuf_free(principals); |
return ret; |
return ret; |
} |
} |