/* $OpenBSD: sshsig.c,v 1.33 2023/09/06 23:18:15 djm Exp $ */
/*
* Copyright (c) 2019 Google LLC
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "includes.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "authfd.h"
#include "authfile.h"
#include "log.h"
#include "misc.h"
#include "sshbuf.h"
#include "sshsig.h"
#include "ssherr.h"
#include "sshkey.h"
#include "match.h"
#include "digest.h"
#define SIG_VERSION 0x01
#define MAGIC_PREAMBLE "SSHSIG"
#define MAGIC_PREAMBLE_LEN (sizeof(MAGIC_PREAMBLE) - 1)
#define BEGIN_SIGNATURE "-----BEGIN SSH SIGNATURE-----"
#define END_SIGNATURE "-----END SSH SIGNATURE-----"
#define RSA_SIGN_ALG "rsa-sha2-512" /* XXX maybe make configurable */
#define RSA_SIGN_ALLOWED "rsa-sha2-512,rsa-sha2-256"
#define HASHALG_DEFAULT "sha512" /* XXX maybe make configurable */
#define HASHALG_ALLOWED "sha256,sha512"
int
sshsig_armor(const struct sshbuf *blob, struct sshbuf **out)
{
struct sshbuf *buf = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
*out = NULL;
if ((buf = sshbuf_new()) == NULL) {
error_f("sshbuf_new failed");
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbuf_putf(buf, "%s\n", BEGIN_SIGNATURE)) != 0) {
error_fr(r, "sshbuf_putf");
goto out;
}
if ((r = sshbuf_dtob64(blob, buf, 1)) != 0) {
error_fr(r, "base64 encode signature");
goto out;
}
if ((r = sshbuf_put(buf, END_SIGNATURE,
sizeof(END_SIGNATURE)-1)) != 0 ||
(r = sshbuf_put_u8(buf, '\n')) != 0) {
error_fr(r, "sshbuf_put");
goto out;
}
/* success */
*out = buf;
buf = NULL; /* transferred */
r = 0;
out:
sshbuf_free(buf);
return r;
}
int
sshsig_dearmor(struct sshbuf *sig, struct sshbuf **out)
{
int r;
size_t eoffset = 0;
struct sshbuf *buf = NULL;
struct sshbuf *sbuf = NULL;
char *b64 = NULL;
if ((sbuf = sshbuf_fromb(sig)) == NULL) {
error_f("sshbuf_fromb failed");
return SSH_ERR_ALLOC_FAIL;
}
/* Expect and consume preamble + lf/crlf */
if ((r = sshbuf_cmp(sbuf, 0,
BEGIN_SIGNATURE, sizeof(BEGIN_SIGNATURE)-1)) != 0) {
error("Couldn't parse signature: missing header");
goto done;
}
if ((r = sshbuf_consume(sbu