-/* $OpenBSD: sshkey.c,v 1.66 2018/07/03 13:20:25 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.67 2018/09/12 01:31:30 djm Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
struct sshbuf *buf, enum sshkey_serialize_rep);
static int sshkey_from_blob_internal(struct sshbuf *buf,
struct sshkey **keyp, int allow_cert);
+static int get_sigtype(const u_char *sig, size_t siglen, char **sigtypep);
/* Supported key types */
struct keytype {
free(cert->principals[i]);
free(cert->principals);
sshkey_free(cert->signature_key);
+ free(cert->signature_type);
freezero(cert, sizeof(*cert));
}
cert->key_id = NULL;
cert->principals = NULL;
cert->signature_key = NULL;
+ cert->signature_type = NULL;
return cert;
}
u_int i;
const struct sshkey_cert *from;
struct sshkey_cert *to;
- int ret = SSH_ERR_INTERNAL_ERROR;
-
- if (to_key->cert != NULL) {
- cert_free(to_key->cert);
- to_key->cert = NULL;
- }
+ int r = SSH_ERR_INTERNAL_ERROR;
- if ((from = from_key->cert) == NULL)
+ if (to_key == NULL || (from = from_key->cert) == NULL)
return SSH_ERR_INVALID_ARGUMENT;
- if ((to = to_key->cert = cert_new()) == NULL)
+ if ((to = cert_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
- if ((ret = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
- (ret = sshbuf_putb(to->critical, from->critical)) != 0 ||
- (ret = sshbuf_putb(to->extensions, from->extensions)) != 0)
- return ret;
+ if ((r = sshbuf_putb(to->certblob, from->certblob)) != 0 ||
+ (r = sshbuf_putb(to->critical, from->critical)) != 0 ||
+ (r = sshbuf_putb(to->extensions, from->extensions)) != 0)
+ goto out;
to->serial = from->serial;
to->type = from->type;
if (from->key_id == NULL)
to->key_id = NULL;
- else if ((to->key_id = strdup(from->key_id)) == NULL)
- return SSH_ERR_ALLOC_FAIL;
+ else if ((to->key_id = strdup(from->key_id)) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
to->valid_after = from->valid_after;
to->valid_before = from->valid_before;
if (from->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)
- return ret;
-
- if (from->nprincipals > SSHKEY_CERT_MAX_PRINCIPALS)
- return SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+ if (from->signature_type != NULL &&
+ (to->signature_type = strdup(from->signature_type)) == NULL) {
+ 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 ((to->principals = calloc(from->nprincipals,
- sizeof(*to->principals))) == NULL)
- return SSH_ERR_ALLOC_FAIL;
+ sizeof(*to->principals))) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
for (i = 0; i < from->nprincipals; i++) {
to->principals[i] = strdup(from->principals[i]);
if (to->principals[i] == NULL) {
to->nprincipals = i;
- return SSH_ERR_ALLOC_FAIL;
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
}
}
}
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
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0)
goto out;
+ if ((ret = get_sigtype(sig, slen, &key->cert->signature_type)) != 0)
+ goto out;
/* Success */
ret = 0;
u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
size_t i, ca_len, sig_len;
int ret = SSH_ERR_INTERNAL_ERROR;
- struct sshbuf *cert;
+ struct sshbuf *cert = NULL;
+ char *sigtype = NULL;
if (k == NULL || k->cert == NULL ||
k->cert->certblob == NULL || ca == NULL)
if (!sshkey_type_is_valid_ca(ca->type))
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)
return SSH_ERR_KEY_CERT_INVALID_SIGN_KEY;
if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
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 */
if ((ret = sshbuf_put_string(cert, sig_blob, sig_len)) != 0)
goto out;
sshbuf_reset(cert);
free(sig_blob);
free(ca_blob);
+ free(sigtype);
sshbuf_free(principals);
return ret;
}