/* $OpenBSD: sshkey-xmss.c,v 1.6 2019/10/09 00:02:57 djm Exp $ */
/*
* Copyright (c) 2017 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#ifdef WITH_XMSS
#include <sys/types.h>
#include <sys/uio.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#include "ssh2.h"
#include "ssherr.h"
#include "sshbuf.h"
#include "cipher.h"
#include "sshkey.h"
#include "sshkey-xmss.h"
#include "atomicio.h"
#include "xmss_fast.h"
/* opaque internal XMSS state */
#define XMSS_MAGIC "xmss-state-v1"
#define XMSS_CIPHERNAME "aes256-gcm@openssh.com"
struct ssh_xmss_state {
xmss_params params;
u_int32_t n, w, h, k;
bds_state bds;
u_char *stack;
u_int32_t stackoffset;
u_char *stacklevels;
u_char *auth;
u_char *keep;
u_char *th_nodes;
u_char *retain;
treehash_inst *treehash;
u_int32_t idx; /* state read from file */
u_int32_t maxidx; /* restricted # of signatures */
int have_state; /* .state file exists */
int lockfd; /* locked in sshkey_xmss_get_state() */
int allow_update; /* allow sshkey_xmss_update_state() */
char *enc_ciphername;/* encrypt state with cipher */
u_char *enc_keyiv; /* encrypt state with key */
u_int32_t enc_keyiv_len; /* length of enc_keyiv */
};
int sshkey_xmss_init_bds_state(struct sshkey *);
int sshkey_xmss_init_enc_key(struct sshkey *, const char *);
void sshkey_xmss_free_bds(struct sshkey *);
int sshkey_xmss_get_state_from_file(struct sshkey *, const char *,
int *, sshkey_printfn *);
int sshkey_xmss_encrypt_state(const struct sshkey *, struct sshbuf *,
struct sshbuf **);
int sshkey_xmss_decrypt_state(const struct sshkey *, struct sshbuf *,
struct sshbuf **);
int sshkey_xmss_serialize_enc_key(const struct sshkey *, struct sshbuf *);
int sshkey_xmss_deserialize_enc_key(struct sshkey *, struct sshbuf *);
#define PRINT(s...) do { if (pr) pr(s); } while (0)
int
sshkey_xmss_init(struct sshkey *key, const char *name)
{
struct ssh_xmss_state *state;
if (key->xmss_state != NULL)
return SSH_ERR_INVALID_FORMAT;
if (name == NULL)
return SSH_ERR_INVALID_FORMAT;
state = calloc(sizeof(struct ssh_xmss_state), 1);
if (state == NULL)
return SSH_ERR_ALLOC_FAIL;
if (strcmp(name, XMSS_SHA2_256_W16_H10_NAME) == 0) {
state->n = 32;
state->w = 16;
state->h = 10;
} else if (strcmp(name, XMSS_SHA2_256_W16_H16_NAME) == 0) {
state->n = 32;
state->w = 16;
state->h = 16;
} else if (strcmp(name, XMSS_SHA2_256_W16_H20_NAME) == 0) {
state->n = 32;
state->w = 16;
state->h = 20;
} else {
free(state);
return SSH_ERR_KEY_TYPE_UNKNOWN;
}
if ((key->xmss_name