From f290ab0833e44355fc006e4e67b92446c14673ef Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Wed, 8 Apr 2020 00:08:46 +0000 Subject: [PATCH] upstream: add sshkey_parse_pubkey_from_private_fileblob_type() Extracts a public key from the unencrypted envelope of a new-style OpenSSH private key. ok markus@ OpenBSD-Commit-ID: 44d7ab446e5e8c686aee96d5897b26b3939939aa --- sshkey.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- sshkey.h | 4 +++- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/sshkey.c b/sshkey.c index e87572c17..d6cc6365f 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.106 2020/04/08 00:07:19 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.107 2020/04/08 00:08:46 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -4366,6 +4366,56 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, return r; } +static int +sshkey_parse_private2_pubkey(struct sshbuf *blob, int type, + struct sshkey **keyp) +{ + int r = SSH_ERR_INTERNAL_ERROR; + struct sshbuf *decoded = NULL; + struct sshkey *pubkey = NULL; + u_int nkeys = 0; + + if (keyp != NULL) + *keyp = NULL; + + if ((r = private2_uudecode(blob, &decoded)) != 0) + goto out; + /* parse public key from unencrypted envelope */ + if ((r = sshbuf_consume(decoded, sizeof(AUTH_MAGIC))) != 0 || + (r = sshbuf_skip_string(decoded)) != 0 || /* cipher */ + (r = sshbuf_skip_string(decoded)) != 0 || /* KDF alg */ + (r = sshbuf_skip_string(decoded)) != 0 || /* KDF hint */ + (r = sshbuf_get_u32(decoded, &nkeys)) != 0) + goto out; + + if (nkeys != 1) { + /* XXX only one key supported at present */ + r = SSH_ERR_INVALID_FORMAT; + goto out; + } + + /* Parse the public key */ + if ((r = sshkey_froms(decoded, &pubkey)) != 0) + goto out; + + if (type != KEY_UNSPEC && + sshkey_type_plain(type) != sshkey_type_plain(pubkey->type)) { + r = SSH_ERR_KEY_TYPE_MISMATCH; + goto out; + } + + /* success */ + r = 0; + if (keyp != NULL) { + *keyp = pubkey; + pubkey = NULL; + } + out: + sshbuf_free(decoded); + sshkey_free(pubkey); + return r; +} + #ifdef WITH_OPENSSL /* convert SSH v2 key to PEM or PKCS#8 format */ static int @@ -4730,6 +4780,20 @@ sshkey_sig_details_free(struct sshkey_sig_details *details) freezero(details, sizeof(*details)); } +int +sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, int type, + struct sshkey **pubkeyp) +{ + int r = SSH_ERR_INTERNAL_ERROR; + + if (pubkeyp != NULL) + *pubkeyp = NULL; + /* only new-format private keys bundle a public key inside */ + if ((r = sshkey_parse_private2_pubkey(blob, type, pubkeyp)) != 0) + return r; + return 0; +} + #ifdef WITH_XMSS /* * serialize the key with the current state and forward the state diff --git a/sshkey.h b/sshkey.h index 71a3fddcb..9c1d4f637 100644 --- a/sshkey.h +++ b/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.44 2019/12/30 09:23:28 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.45 2020/04/08 00:08:46 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -259,6 +259,8 @@ int sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase, struct sshkey **keyp, char **commentp); int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, const char *passphrase, struct sshkey **keyp, char **commentp); +int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, + int type, struct sshkey **pubkeyp); /* XXX should be internal, but used by ssh-keygen */ int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *);