Skip to content

Commit

Permalink
upstream: allow key revocation by SHA256 hash and allow ssh-keygen
Browse files Browse the repository at this point in the history
to create KRLs using SHA256/base64 key fingerprints; ok markus@

OpenBSD-Commit-ID: a0590fd34e7f1141f2873ab3acc57442560e6a94
  • Loading branch information
djmdjm committed Sep 12, 2018
1 parent 50e2687 commit 9405c62
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 49 deletions.
16 changes: 9 additions & 7 deletions PROTOCOL.krl
Expand Up @@ -36,6 +36,7 @@ The available section types are:
#define KRL_SECTION_EXPLICIT_KEY 2
#define KRL_SECTION_FINGERPRINT_SHA1 3
#define KRL_SECTION_SIGNATURE 4
#define KRL_SECTION_FINGERPRINT_SHA256 5

2. Certificate section

Expand Down Expand Up @@ -127,18 +128,19 @@ must be a raw key (i.e. not a certificate).

This section may appear multiple times.

4. SHA1 fingerprint sections
4. SHA1/SHA256 fingerprint sections

These sections, identified as KRL_SECTION_FINGERPRINT_SHA1, revoke
plain keys (i.e. not certificates) by listing their SHA1 hashes:
These sections, identified as KRL_SECTION_FINGERPRINT_SHA1 and
KRL_SECTION_FINGERPRINT_SHA256, revoke plain keys (i.e. not
certificates) by listing their hashes:

string public_key_hash[0]
....

This section must contain at least one "public_key_hash". The hash blob
is obtained by taking the SHA1 hash of the public key blob. Hashes in
this section must appear in numeric order, treating each hash as a big-
endian integer.
is obtained by taking the SHA1 or SHA256 hash of the public key blob.
Hashes in this section must appear in numeric order, treating each hash
as a big-endian integer.

This section may appear multiple times.

Expand Down Expand Up @@ -166,4 +168,4 @@ Implementations that retrieve KRLs over untrusted channels must verify
signatures. Signature sections are optional for KRLs distributed by
trusted means.

$OpenBSD: PROTOCOL.krl,v 1.4 2018/04/10 00:10:49 djm Exp $
$OpenBSD: PROTOCOL.krl,v 1.5 2018/09/12 01:21:34 djm Exp $
126 changes: 97 additions & 29 deletions krl.c
Expand Up @@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/* $OpenBSD: krl.c,v 1.41 2017/12/18 02:25:15 djm Exp $ */
/* $OpenBSD: krl.c,v 1.42 2018/09/12 01:21:34 djm Exp $ */

#include "includes.h"

Expand Down Expand Up @@ -96,6 +96,7 @@ struct ssh_krl {
char *comment;
struct revoked_blob_tree revoked_keys;
struct revoked_blob_tree revoked_sha1s;
struct revoked_blob_tree revoked_sha256s;
struct revoked_certs_list revoked_certs;
};

Expand Down Expand Up @@ -136,6 +137,7 @@ ssh_krl_init(void)
return NULL;
RB_INIT(&krl->revoked_keys);
RB_INIT(&krl->revoked_sha1s);
RB_INIT(&krl->revoked_sha256s);
TAILQ_INIT(&krl->revoked_certs);
return krl;
}
Expand Down Expand Up @@ -178,6 +180,11 @@ ssh_krl_free(struct ssh_krl *krl)
free(rb->blob);
free(rb);
}
RB_FOREACH_SAFE(rb, revoked_blob_tree, &krl->revoked_sha256s, trb) {
RB_REMOVE(revoked_blob_tree, &krl->revoked_sha256s, rb);
free(rb->blob);
free(rb);
}
TAILQ_FOREACH_SAFE(rc, &krl->revoked_certs, entry, trc) {
TAILQ_REMOVE(&krl->revoked_certs, rc, entry);
revoked_certs_free(rc);
Expand Down Expand Up @@ -408,25 +415,47 @@ ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key)
return revoke_blob(&krl->revoked_keys, blob, len);
}

int
ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key)
static int
revoke_by_hash(struct revoked_blob_tree *target, const u_char *p, size_t len)
{
u_char *blob;
size_t len;
int r;

debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key));
if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
&blob, &len)) != 0)
/* need to copy hash, as revoke_blob steals ownership */
if ((blob = malloc(len)) == NULL)
return SSH_ERR_SYSTEM_ERROR;
memcpy(blob, p, len);
if ((r = revoke_blob(target, blob, len)) != 0) {
free(blob);
return r;
return revoke_blob(&krl->revoked_sha1s, blob, len);
}
return 0;
}

int
ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len)
{
debug3("%s: revoke by sha1", __func__);
if (len != 20)
return SSH_ERR_INVALID_FORMAT;
return revoke_by_hash(&krl->revoked_sha1s, p, len);
}

int
ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len)
{
debug3("%s: revoke by sha256", __func__);
if (len != 32)
return SSH_ERR_INVALID_FORMAT;
return revoke_by_hash(&krl->revoked_sha256s, p, len);
}

int
ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key)
{
/* XXX replace with SHA256? */
if (!sshkey_is_cert(key))
return ssh_krl_revoke_key_sha1(krl, key);
return ssh_krl_revoke_key_explicit(krl, key);

if (key->cert->serial == 0) {
return ssh_krl_revoke_cert_by_key_id(krl,
Expand Down Expand Up @@ -762,6 +791,18 @@ ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}
sshbuf_reset(sect);
RB_FOREACH(rb, revoked_blob_tree, &krl->revoked_sha256s) {
KRL_DBG(("%s: hash len %zu ", __func__, rb->len));
if ((r = sshbuf_put_string(sect, rb->blob, rb->len)) != 0)
goto out;
}
if (sshbuf_len(sect) != 0) {
if ((r = sshbuf_put_u8(buf,
KRL_SECTION_FINGERPRINT_SHA256)) != 0 ||
(r = sshbuf_put_stringb(buf, sect)) != 0)
goto out;
}

for (i = 0; i < nsign_keys; i++) {
KRL_DBG(("%s: signature key %s", __func__,
Expand Down Expand Up @@ -914,6 +955,29 @@ parse_revoked_certs(struct sshbuf *buf, struct ssh_krl *krl)
return r;
}

static int
blob_section(struct sshbuf *sect, struct revoked_blob_tree *target_tree,
size_t expected_len)
{
u_char *rdata = NULL;
size_t rlen = 0;
int r;

while (sshbuf_len(sect) > 0) {
if ((r = sshbuf_get_string(sect, &rdata, &rlen)) != 0)
return r;
if (expected_len != 0 && rlen != expected_len) {
error("%s: bad length", __func__);
free(rdata);
return SSH_ERR_INVALID_FORMAT;
}
if ((r = revoke_blob(target_tree, rdata, rlen)) != 0) {
free(rdata);
return r;
}
}
return 0;
}

/* Attempt to parse a KRL, checking its signature (if any) with sign_ca_keys. */
int
Expand All @@ -925,9 +989,9 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
char timestamp[64];
int r = SSH_ERR_INTERNAL_ERROR, sig_seen;
struct sshkey *key = NULL, **ca_used = NULL, **tmp_ca_used;
u_char type, *rdata = NULL;
u_char type;
const u_char *blob;
size_t i, j, sig_off, sects_off, rlen, blen, nca_used;
size_t i, j, sig_off, sects_off, blen, nca_used;
u_int format_version;

nca_used = 0;
Expand Down Expand Up @@ -1068,24 +1132,19 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
goto out;
break;
case KRL_SECTION_EXPLICIT_KEY:
if ((r = blob_section(sect,
&krl->revoked_keys, 0)) != 0)
goto out;
break;
case KRL_SECTION_FINGERPRINT_SHA1:
while (sshbuf_len(sect) > 0) {
if ((r = sshbuf_get_string(sect,
&rdata, &rlen)) != 0)
goto out;
if (type == KRL_SECTION_FINGERPRINT_SHA1 &&
rlen != 20) {
error("%s: bad SHA1 length", __func__);
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
if ((r = revoke_blob(
type == KRL_SECTION_EXPLICIT_KEY ?
&krl->revoked_keys : &krl->revoked_sha1s,
rdata, rlen)) != 0)
goto out;
rdata = NULL; /* revoke_blob frees rdata */
}
if ((r = blob_section(sect,
&krl->revoked_sha1s, 20)) != 0)
goto out;
break;
case KRL_SECTION_FINGERPRINT_SHA256:
if ((r = blob_section(sect,
&krl->revoked_sha256s, 32)) != 0)
goto out;
break;
case KRL_SECTION_SIGNATURE:
/* Handled above, but still need to stay in synch */
Expand Down Expand Up @@ -1150,7 +1209,6 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
for (i = 0; i < nca_used; i++)
sshkey_free(ca_used[i]);
free(ca_used);
free(rdata);
sshkey_free(key);
sshbuf_free(copy);
sshbuf_free(sect);
Expand Down Expand Up @@ -1210,6 +1268,16 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
KRL_DBG(("%s: revoked by key SHA1", __func__));
return SSH_ERR_KEY_REVOKED;
}
memset(&rb, 0, sizeof(rb));
if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA256,
&rb.blob, &rb.len)) != 0)
return r;
erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb);
free(rb.blob);
if (erb != NULL) {
KRL_DBG(("%s: revoked by key SHA256", __func__));
return SSH_ERR_KEY_REVOKED;
}

/* Next, explicit keys */
memset(&rb, 0, sizeof(rb));
Expand Down
6 changes: 4 additions & 2 deletions krl.h
Expand Up @@ -14,7 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/* $OpenBSD: krl.h,v 1.5 2015/12/30 23:46:14 djm Exp $ */
/* $OpenBSD: krl.h,v 1.6 2018/09/12 01:21:34 djm Exp $ */

#ifndef _KRL_H
#define _KRL_H
Expand All @@ -29,6 +29,7 @@
#define KRL_SECTION_EXPLICIT_KEY 2
#define KRL_SECTION_FINGERPRINT_SHA1 3
#define KRL_SECTION_SIGNATURE 4
#define KRL_SECTION_FINGERPRINT_SHA256 5

/* KRL_SECTION_CERTIFICATES subsection types */
#define KRL_SECTION_CERT_SERIAL_LIST 0x20
Expand All @@ -51,7 +52,8 @@ int ssh_krl_revoke_cert_by_serial_range(struct ssh_krl *krl,
int ssh_krl_revoke_cert_by_key_id(struct ssh_krl *krl,
const struct sshkey *ca_key, const char *key_id);
int ssh_krl_revoke_key_explicit(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len);
int ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len);
int ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key);
int ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
const struct sshkey **sign_keys, u_int nsign_keys);
Expand Down
19 changes: 16 additions & 3 deletions ssh-keygen.1
@@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.148 2018/08/08 01:16:01 djm Exp $
.\" $OpenBSD: ssh-keygen.1,v 1.149 2018/09/12 01:21:34 djm Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
Expand Down Expand Up @@ -35,7 +35,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: August 8 2018 $
.Dd $Mdocdate: September 12 2018 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
Expand Down Expand Up @@ -814,7 +814,20 @@ option.
Revokes the specified key.
If a certificate is listed, then it is revoked as a plain public key.
.It Cm sha1 : Ar public_key
Revokes the specified key by its SHA1 hash.
Revokes the specified key by including its SHA1 hash in the KRL.
.It Cm sha256 : Ar public_key
Revokes the specified key by including its SHA256 hash in the KRL.
KRLs that revoke keys by SHA256 hash are not supported by OpenSSH versions
prior to 7.9.
.It Cm hash : Ar fingerprint
Revokes a key using by fingerprint hash, as obtained from a
.Xr sshd 8
authentication log message or the
.Nm
.Fl l
flag.
Only SHA256 fingerprints are supported here and resultant KRLs are
not supported by OpenSSH versions prior to 7.9.
.El
.Pp
KRLs may be updated using the
Expand Down

0 comments on commit 9405c62

Please sign in to comment.