003 File Manager
Current Path:
/usr/src/crypto/openssh
usr
/
src
/
crypto
/
openssh
/
📁
..
📄
.depend
(129.94 KB)
📄
.gitignore
(341 B)
📄
.skipped-commit-ids
(1.85 KB)
📄
CREDITS
(5.36 KB)
📄
ChangeLog
(299.53 KB)
📄
FREEBSD-upgrade
(5.68 KB)
📄
FREEBSD-vendor
(131 B)
📄
INSTALL
(9.36 KB)
📄
LICENCE
(14.83 KB)
📄
Makefile.in
(24.73 KB)
📄
OVERVIEW
(6.16 KB)
📄
PROTOCOL
(18 KB)
📄
PROTOCOL.agent
(220 B)
📄
PROTOCOL.certkeys
(11.91 KB)
📄
PROTOCOL.chacha20poly1305
(4.52 KB)
📄
PROTOCOL.key
(1.5 KB)
📄
PROTOCOL.krl
(5.13 KB)
📄
PROTOCOL.mux
(8.87 KB)
📄
README
(2.39 KB)
📄
README.dns
(1.57 KB)
📄
README.platform
(3.95 KB)
📄
README.privsep
(2.25 KB)
📄
README.tun
(4.78 KB)
📄
TODO
(2.54 KB)
📄
aclocal.m4
(5.56 KB)
📄
addrmatch.c
(10.97 KB)
📄
atomicio.c
(4.4 KB)
📄
atomicio.h
(2.14 KB)
📄
audit-bsm.c
(11.82 KB)
📄
audit-linux.c
(3.46 KB)
📄
audit.c
(5.69 KB)
📄
audit.h
(2.27 KB)
📄
auth-bsdauth.c
(3.65 KB)
📄
auth-krb5.c
(6.93 KB)
📄
auth-options.c
(23.45 KB)
📄
auth-options.h
(2.75 KB)
📄
auth-pam.c
(35.07 KB)
📄
auth-pam.h
(1.89 KB)
📄
auth-passwd.c
(6.42 KB)
📄
auth-rhosts.c
(8.89 KB)
📄
auth-shadow.c
(4.25 KB)
📄
auth-sia.c
(3.15 KB)
📄
auth-sia.h
(1.4 KB)
📄
auth-skey.c
(2.75 KB)
📄
auth.c
(32.86 KB)
📄
auth.h
(7.95 KB)
📄
auth2-chall.c
(9.77 KB)
📄
auth2-gss.c
(9.63 KB)
📄
auth2-hostbased.c
(8.08 KB)
📄
auth2-kbdint.c
(2.2 KB)
📄
auth2-none.c
(2.29 KB)
📄
auth2-passwd.c
(2.36 KB)
📄
auth2-pubkey.c
(28.79 KB)
📄
auth2.c
(22.23 KB)
📄
authfd.c
(14.47 KB)
📄
authfd.h
(3.05 KB)
📄
authfile.c
(12.59 KB)
📄
authfile.h
(2.34 KB)
📄
bitmap.c
(4.44 KB)
📄
bitmap.h
(1.9 KB)
📄
blacklist.c
(2.81 KB)
📄
blacklist_client.h
(2.09 KB)
📄
buildpkg.sh.in
(17.64 KB)
📄
canohost.c
(4.72 KB)
📄
canohost.h
(842 B)
📄
chacha.c
(5.28 KB)
📄
chacha.h
(1000 B)
📄
channels.c
(133.25 KB)
📄
channels.h
(12.96 KB)
📄
cipher-aes.c
(4.54 KB)
📄
cipher-aesctr.c
(2.06 KB)
📄
cipher-aesctr.h
(1.3 KB)
📄
cipher-chachapoly.c
(3.72 KB)
📄
cipher-chachapoly.h
(1.58 KB)
📄
cipher-ctr.c
(3.57 KB)
📄
cipher.c
(13.57 KB)
📄
cipher.h
(3.15 KB)
📄
cleanup.c
(1.01 KB)
📄
clientloop.c
(66.05 KB)
📄
clientloop.h
(3.69 KB)
📄
compat.c
(6.62 KB)
📄
compat.h
(2.77 KB)
📄
config.guess
(42.74 KB)
📄
config.h
(53.02 KB)
📄
config.sub
(35.49 KB)
📄
configure.ac
(147.81 KB)
📁
contrib
📄
crc32.c
(4.92 KB)
📄
crc32.h
(1.44 KB)
📄
crypto_api.h
(1.12 KB)
📄
defines.h
(21.73 KB)
📄
dh.c
(15.14 KB)
📄
dh.h
(2.59 KB)
📄
digest-libc.c
(5.69 KB)
📄
digest-openssl.c
(4.95 KB)
📄
digest.h
(2.51 KB)
📄
dispatch.c
(3.52 KB)
📄
dispatch.h
(2.2 KB)
📄
dns.c
(9.15 KB)
📄
dns.h
(2.03 KB)
📄
ed25519.c
(3.1 KB)
📄
entropy.c
(6.34 KB)
📄
entropy.h
(1.47 KB)
📄
fatal.c
(1.63 KB)
📄
fe25519.c
(8.13 KB)
📄
fe25519.h
(2.31 KB)
📄
fixalgorithms
(422 B)
📄
fixpaths
(499 B)
📄
freebsd-configure.sh
(1.07 KB)
📄
freebsd-namespace.sh
(1.93 KB)
📄
freebsd-post-merge.sh
(224 B)
📄
freebsd-pre-merge.sh
(429 B)
📄
ge25519.c
(11.04 KB)
📄
ge25519.h
(1.35 KB)
📄
ge25519_base.data
(164.61 KB)
📄
groupaccess.c
(3.5 KB)
📄
groupaccess.h
(1.53 KB)
📄
gss-genr.c
(7.99 KB)
📄
gss-serv-krb5.c
(5.63 KB)
📄
gss-serv.c
(10.32 KB)
📄
hash.c
(623 B)
📄
hmac.c
(5.08 KB)
📄
hmac.h
(1.62 KB)
📄
hostfile.c
(21.7 KB)
📄
hostfile.h
(3.8 KB)
📄
includes.h
(3.85 KB)
📄
install-sh
(13.67 KB)
📄
kex.c
(25.9 KB)
📄
kex.h
(7.32 KB)
📄
kexc25519.c
(4.62 KB)
📄
kexc25519c.c
(5.11 KB)
📄
kexc25519s.c
(4.99 KB)
📄
kexdh.c
(3.27 KB)
📄
kexdhc.c
(6.13 KB)
📄
kexdhs.c
(6.06 KB)
📄
kexecdh.c
(3.49 KB)
📄
kexecdhc.c
(6.22 KB)
📄
kexecdhs.c
(5.94 KB)
📄
kexgex.c
(3.67 KB)
📄
kexgexc.c
(7.63 KB)
📄
kexgexs.c
(7.35 KB)
📄
krb5_config.h
(315 B)
📄
krl.c
(35.63 KB)
📄
krl.h
(2.67 KB)
📄
log.c
(10.67 KB)
📄
log.h
(2.64 KB)
📄
loginrec.c
(41.91 KB)
📄
loginrec.h
(4.6 KB)
📄
logintest.c
(8.58 KB)
📄
mac.c
(7.24 KB)
📄
mac.h
(1.96 KB)
📄
match.c
(9.14 KB)
📄
match.h
(1.16 KB)
📄
md5crypt.c
(3.98 KB)
📄
md5crypt.h
(744 B)
📄
mdoc2man.awk
(8.38 KB)
📄
misc.c
(43.77 KB)
📄
misc.h
(5.69 KB)
📄
mkinstalldirs
(633 B)
📄
moduli
(552 KB)
📄
moduli.5
(3.6 KB)
📄
moduli.c
(20.46 KB)
📄
monitor.c
(50.56 KB)
📄
monitor.h
(3.83 KB)
📄
monitor_fdpass.c
(4.71 KB)
📄
monitor_fdpass.h
(1.49 KB)
📄
monitor_wrap.c
(27.44 KB)
📄
monitor_wrap.h
(3.84 KB)
📄
msg.c
(2.75 KB)
📄
msg.h
(1.49 KB)
📄
mux.c
(65.73 KB)
📄
myproposal.h
(5.62 KB)
📄
nchan.c
(12.06 KB)
📄
nchan.ms
(3.86 KB)
📄
nchan2.ms
(3.38 KB)
📄
opacket.c
(5.55 KB)
📄
opacket.h
(5.98 KB)
📁
openbsd-compat
📄
openssh.xml.in
(2.77 KB)
📄
opensshd.init.in
(1.86 KB)
📄
packet.c
(70.79 KB)
📄
packet.h
(7.39 KB)
📄
pathnames.h
(5.69 KB)
📄
pkcs11.h
(41.37 KB)
📄
platform-misc.c
(1.09 KB)
📄
platform-pledge.c
(1.86 KB)
📄
platform-tracing.c
(1.69 KB)
📄
platform.c
(4.71 KB)
📄
platform.h
(1.43 KB)
📄
poly1305.c
(4.54 KB)
📄
poly1305.h
(645 B)
📄
progressmeter.c
(7.48 KB)
📄
progressmeter.h
(1.44 KB)
📄
readconf.c
(81 KB)
📄
readconf.h
(7.83 KB)
📄
readpass.c
(4.99 KB)
📁
regress
📄
rijndael.c
(51.57 KB)
📄
rijndael.h
(2.07 KB)
📄
sandbox-capsicum.c
(3.39 KB)
📄
sandbox-darwin.c
(2.49 KB)
📄
sandbox-null.c
(1.62 KB)
📄
sandbox-pledge.c
(1.83 KB)
📄
sandbox-rlimit.c
(2.43 KB)
📄
sandbox-seccomp-filter.c
(9.88 KB)
📄
sandbox-solaris.c
(2.9 KB)
📄
sandbox-systrace.c
(6.27 KB)
📄
sc25519.c
(7.16 KB)
📄
sc25519.h
(2.83 KB)
📄
scp.1
(5.56 KB)
📄
scp.c
(39.14 KB)
📄
servconf.c
(79.73 KB)
📄
servconf.h
(10.13 KB)
📄
serverloop.c
(26.03 KB)
📄
serverloop.h
(1000 B)
📄
session.c
(66.72 KB)
📄
session.h
(2.59 KB)
📄
sftp-client.c
(49.62 KB)
📄
sftp-client.h
(4.29 KB)
📄
sftp-common.c
(6.83 KB)
📄
sftp-common.h
(2.02 KB)
📄
sftp-glob.c
(3.38 KB)
📄
sftp-server-main.c
(1.49 KB)
📄
sftp-server.8
(4.98 KB)
📄
sftp-server.c
(42.36 KB)
📄
sftp.1
(14.53 KB)
📄
sftp.c
(59.73 KB)
📄
sftp.h
(3.33 KB)
📄
smult_curve25519_ref.c
(6.71 KB)
📄
ssh-add.1
(6.45 KB)
📄
ssh-add.c
(17.69 KB)
📄
ssh-agent.1
(7.16 KB)
📄
ssh-agent.c
(33.19 KB)
📄
ssh-dss.c
(5.55 KB)
📄
ssh-ecdsa.c
(5.54 KB)
📄
ssh-ed25519.c
(4.21 KB)
📄
ssh-gss.h
(4.71 KB)
📄
ssh-keygen.1
(26.5 KB)
📄
ssh-keygen.c
(78.58 KB)
📄
ssh-keyscan.1
(3.82 KB)
📄
ssh-keyscan.c
(17.83 KB)
📄
ssh-keysign.8
(2.95 KB)
📄
ssh-keysign.c
(8.26 KB)
📄
ssh-pkcs11-client.c
(6.65 KB)
📄
ssh-pkcs11-helper.8
(1.33 KB)
📄
ssh-pkcs11-helper.c
(9.79 KB)
📄
ssh-pkcs11.c
(19.56 KB)
📄
ssh-pkcs11.h
(1.06 KB)
📄
ssh-rsa.c
(11.89 KB)
📄
ssh-sandbox.h
(1.09 KB)
📄
ssh-xmss.c
(5 KB)
📄
ssh.1
(44.3 KB)
📄
ssh.c
(61.58 KB)
📄
ssh.h
(2.6 KB)
📄
ssh2.h
(5.66 KB)
📄
ssh_api.c
(13.81 KB)
📄
ssh_api.h
(4.33 KB)
📄
ssh_config
(1.53 KB)
📄
ssh_config.5
(51.41 KB)
📄
ssh_namespace.h
(44.25 KB)
📄
sshbuf-getput-basic.c
(11.81 KB)
📄
sshbuf-getput-crypto.c
(5.64 KB)
📄
sshbuf-misc.c
(3.53 KB)
📄
sshbuf.c
(8.96 KB)
📄
sshbuf.h
(12.2 KB)
📄
sshconnect.c
(43.92 KB)
📄
sshconnect.h
(2.3 KB)
📄
sshconnect2.c
(59.05 KB)
📄
sshd.8
(30.87 KB)
📄
sshd.c
(64.58 KB)
📄
sshd_config
(3.18 KB)
📄
sshd_config.5
(50.55 KB)
📄
ssherr.c
(5.04 KB)
📄
ssherr.h
(3.28 KB)
📄
sshkey-xmss.c
(28.17 KB)
📄
sshkey-xmss.h
(2.89 KB)
📄
sshkey.c
(102.94 KB)
📄
sshkey.h
(10.09 KB)
📄
sshlogin.c
(5.25 KB)
📄
sshlogin.h
(935 B)
📄
sshpty.c
(5.59 KB)
📄
sshpty.h
(1.03 KB)
📄
sshtty.c
(2.95 KB)
📄
survey.sh.in
(1.68 KB)
📄
ttymodes.c
(10.1 KB)
📄
ttymodes.h
(4.85 KB)
📄
uidswap.c
(7.09 KB)
📄
uidswap.h
(680 B)
📄
umac.c
(44.91 KB)
📄
umac.h
(4.58 KB)
📄
umac128.c
(414 B)
📄
utf8.c
(8.09 KB)
📄
utf8.h
(1.17 KB)
📄
uuencode.c
(2.94 KB)
📄
uuencode.h
(1.5 KB)
📄
verify.c
(668 B)
📄
version.h
(385 B)
📄
xmalloc.c
(2.41 KB)
📄
xmalloc.h
(1.08 KB)
📄
xmss_commons.c
(630 B)
📄
xmss_commons.h
(450 B)
📄
xmss_fast.c
(32.16 KB)
📄
xmss_fast.h
(3.64 KB)
📄
xmss_hash.c
(3.35 KB)
📄
xmss_hash.h
(841 B)
📄
xmss_hash_address.c
(1.2 KB)
📄
xmss_hash_address.h
(836 B)
📄
xmss_wots.c
(4.74 KB)
📄
xmss_wots.h
(1.86 KB)
Editing: sshkey-xmss.c
/* $OpenBSD: sshkey-xmss.c,v 1.3 2018/07/09 21:59:10 markus 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 = strdup(name)) == NULL) { free(state); return SSH_ERR_ALLOC_FAIL; } state->k = 2; /* XXX hardcoded */ state->lockfd = -1; if (xmss_set_params(&state->params, state->n, state->h, state->w, state->k) != 0) { free(state); return SSH_ERR_INVALID_FORMAT; } key->xmss_state = state; return 0; } void sshkey_xmss_free_state(struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; sshkey_xmss_free_bds(key); if (state) { if (state->enc_keyiv) { explicit_bzero(state->enc_keyiv, state->enc_keyiv_len); free(state->enc_keyiv); } free(state->enc_ciphername); free(state); } key->xmss_state = NULL; } #define SSH_XMSS_K2_MAGIC "k=2" #define num_stack(x) ((x->h+1)*(x->n)) #define num_stacklevels(x) (x->h+1) #define num_auth(x) ((x->h)*(x->n)) #define num_keep(x) ((x->h >> 1)*(x->n)) #define num_th_nodes(x) ((x->h - x->k)*(x->n)) #define num_retain(x) (((1ULL << x->k) - x->k - 1) * (x->n)) #define num_treehash(x) ((x->h) - (x->k)) int sshkey_xmss_init_bds_state(struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; u_int32_t i; state->stackoffset = 0; if ((state->stack = calloc(num_stack(state), 1)) == NULL || (state->stacklevels = calloc(num_stacklevels(state), 1))== NULL || (state->auth = calloc(num_auth(state), 1)) == NULL || (state->keep = calloc(num_keep(state), 1)) == NULL || (state->th_nodes = calloc(num_th_nodes(state), 1)) == NULL || (state->retain = calloc(num_retain(state), 1)) == NULL || (state->treehash = calloc(num_treehash(state), sizeof(treehash_inst))) == NULL) { sshkey_xmss_free_bds(key); return SSH_ERR_ALLOC_FAIL; } for (i = 0; i < state->h - state->k; i++) state->treehash[i].node = &state->th_nodes[state->n*i]; xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, state->stacklevels, state->auth, state->keep, state->treehash, state->retain, 0); return 0; } void sshkey_xmss_free_bds(struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; if (state == NULL) return; free(state->stack); free(state->stacklevels); free(state->auth); free(state->keep); free(state->th_nodes); free(state->retain); free(state->treehash); state->stack = NULL; state->stacklevels = NULL; state->auth = NULL; state->keep = NULL; state->th_nodes = NULL; state->retain = NULL; state->treehash = NULL; } void * sshkey_xmss_params(const struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; if (state == NULL) return NULL; return &state->params; } void * sshkey_xmss_bds_state(const struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; if (state == NULL) return NULL; return &state->bds; } int sshkey_xmss_siglen(const struct sshkey *key, size_t *lenp) { struct ssh_xmss_state *state = key->xmss_state; if (lenp == NULL) return SSH_ERR_INVALID_ARGUMENT; if (state == NULL) return SSH_ERR_INVALID_FORMAT; *lenp = 4 + state->n + state->params.wots_par.keysize + state->h * state->n; return 0; } size_t sshkey_xmss_pklen(const struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; if (state == NULL) return 0; return state->n * 2; } size_t sshkey_xmss_sklen(const struct sshkey *key) { struct ssh_xmss_state *state = key->xmss_state; if (state == NULL) return 0; return state->n * 4 + 4; } int sshkey_xmss_init_enc_key(struct sshkey *k, const char *ciphername) { struct ssh_xmss_state *state = k->xmss_state; const struct sshcipher *cipher; size_t keylen = 0, ivlen = 0; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((cipher = cipher_by_name(ciphername)) == NULL) return SSH_ERR_INTERNAL_ERROR; if ((state->enc_ciphername = strdup(ciphername)) == NULL) return SSH_ERR_ALLOC_FAIL; keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); state->enc_keyiv_len = keylen + ivlen; if ((state->enc_keyiv = calloc(state->enc_keyiv_len, 1)) == NULL) { free(state->enc_ciphername); state->enc_ciphername = NULL; return SSH_ERR_ALLOC_FAIL; } arc4random_buf(state->enc_keyiv, state->enc_keyiv_len); return 0; } int sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; int r; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 || (r = sshbuf_put_string(b, state->enc_keyiv, state->enc_keyiv_len)) != 0) return r; return 0; } int sshkey_xmss_deserialize_enc_key(struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; size_t len; int r; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_get_cstring(b, &state->enc_ciphername, NULL)) != 0 || (r = sshbuf_get_string(b, &state->enc_keyiv, &len)) != 0) return r; state->enc_keyiv_len = len; return 0; } int sshkey_xmss_serialize_pk_info(const struct sshkey *k, struct sshbuf *b, enum sshkey_serialize_rep opts) { struct ssh_xmss_state *state = k->xmss_state; u_char have_info = 1; u_int32_t idx; int r; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if (opts != SSHKEY_SERIALIZE_INFO) return 0; idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; if ((r = sshbuf_put_u8(b, have_info)) != 0 || (r = sshbuf_put_u32(b, idx)) != 0 || (r = sshbuf_put_u32(b, state->maxidx)) != 0) return r; return 0; } int sshkey_xmss_deserialize_pk_info(struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; u_char have_info; int r; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; /* optional */ if (sshbuf_len(b) == 0) return 0; if ((r = sshbuf_get_u8(b, &have_info)) != 0) return r; if (have_info != 1) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_get_u32(b, &state->idx)) != 0 || (r = sshbuf_get_u32(b, &state->maxidx)) != 0) return r; return 0; } int sshkey_xmss_generate_private_key(struct sshkey *k, u_int bits) { int r; const char *name; if (bits == 10) { name = XMSS_SHA2_256_W16_H10_NAME; } else if (bits == 16) { name = XMSS_SHA2_256_W16_H16_NAME; } else if (bits == 20) { name = XMSS_SHA2_256_W16_H20_NAME; } else { name = XMSS_DEFAULT_NAME; } if ((r = sshkey_xmss_init(k, name)) != 0 || (r = sshkey_xmss_init_bds_state(k)) != 0 || (r = sshkey_xmss_init_enc_key(k, XMSS_CIPHERNAME)) != 0) return r; if ((k->xmss_pk = malloc(sshkey_xmss_pklen(k))) == NULL || (k->xmss_sk = malloc(sshkey_xmss_sklen(k))) == NULL) { return SSH_ERR_ALLOC_FAIL; } xmss_keypair(k->xmss_pk, k->xmss_sk, sshkey_xmss_bds_state(k), sshkey_xmss_params(k)); return 0; } int sshkey_xmss_get_state_from_file(struct sshkey *k, const char *filename, int *have_file, sshkey_printfn *pr) { struct sshbuf *b = NULL, *enc = NULL; int ret = SSH_ERR_SYSTEM_ERROR, r, fd = -1; u_int32_t len; unsigned char buf[4], *data = NULL; *have_file = 0; if ((fd = open(filename, O_RDONLY)) >= 0) { *have_file = 1; if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) { PRINT("%s: corrupt state file: %s", __func__, filename); goto done; } len = PEEK_U32(buf); if ((data = calloc(len, 1)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto done; } if (atomicio(read, fd, data, len) != len) { PRINT("%s: cannot read blob: %s", __func__, filename); goto done; } if ((enc = sshbuf_from(data, len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto done; } sshkey_xmss_free_bds(k); if ((r = sshkey_xmss_decrypt_state(k, enc, &b)) != 0) { ret = r; goto done; } if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) { ret = r; goto done; } ret = 0; } done: if (fd != -1) close(fd); free(data); sshbuf_free(enc); sshbuf_free(b); return ret; } int sshkey_xmss_get_state(const struct sshkey *k, sshkey_printfn *pr) { struct ssh_xmss_state *state = k->xmss_state; u_int32_t idx = 0; char *filename = NULL; char *statefile = NULL, *ostatefile = NULL, *lockfile = NULL; int lockfd = -1, have_state = 0, have_ostate, tries = 0; int ret = SSH_ERR_INVALID_ARGUMENT, r; if (state == NULL) goto done; /* * If maxidx is set, then we are allowed a limited number * of signatures, but don't need to access the disk. * Otherwise we need to deal with the on-disk state. */ if (state->maxidx) { /* xmss_sk always contains the current state */ idx = PEEK_U32(k->xmss_sk); if (idx < state->maxidx) { state->allow_update = 1; return 0; } return SSH_ERR_INVALID_ARGUMENT; } if ((filename = k->xmss_filename) == NULL) goto done; if (asprintf(&lockfile, "%s.lock", filename) < 0 || asprintf(&statefile, "%s.state", filename) < 0 || asprintf(&ostatefile, "%s.ostate", filename) < 0) { ret = SSH_ERR_ALLOC_FAIL; goto done; } if ((lockfd = open(lockfile, O_CREAT|O_RDONLY, 0600)) < 0) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: cannot open/create: %s", __func__, lockfile); goto done; } while (flock(lockfd, LOCK_EX|LOCK_NB) < 0) { if (errno != EWOULDBLOCK) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: cannot lock: %s", __func__, lockfile); goto done; } if (++tries > 10) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: giving up on: %s", __func__, lockfile); goto done; } usleep(1000*100*tries); } /* XXX no longer const */ if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k, statefile, &have_state, pr)) != 0) { if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k, ostatefile, &have_ostate, pr)) == 0) { state->allow_update = 1; r = sshkey_xmss_forward_state(k, 1); state->idx = PEEK_U32(k->xmss_sk); state->allow_update = 0; } } if (!have_state && !have_ostate) { /* check that bds state is initialized */ if (state->bds.auth == NULL) goto done; PRINT("%s: start from scratch idx 0: %u", __func__, state->idx); } else if (r != 0) { ret = r; goto done; } if (state->idx + 1 < state->idx) { PRINT("%s: state wrap: %u", __func__, state->idx); goto done; } state->have_state = have_state; state->lockfd = lockfd; state->allow_update = 1; lockfd = -1; ret = 0; done: if (lockfd != -1) close(lockfd); free(lockfile); free(statefile); free(ostatefile); return ret; } int sshkey_xmss_forward_state(const struct sshkey *k, u_int32_t reserve) { struct ssh_xmss_state *state = k->xmss_state; u_char *sig = NULL; size_t required_siglen; unsigned long long smlen; u_char data; int ret, r; if (state == NULL || !state->allow_update) return SSH_ERR_INVALID_ARGUMENT; if (reserve == 0) return SSH_ERR_INVALID_ARGUMENT; if (state->idx + reserve <= state->idx) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshkey_xmss_siglen(k, &required_siglen)) != 0) return r; if ((sig = malloc(required_siglen)) == NULL) return SSH_ERR_ALLOC_FAIL; while (reserve-- > 0) { state->idx = PEEK_U32(k->xmss_sk); smlen = required_siglen; if ((ret = xmss_sign(k->xmss_sk, sshkey_xmss_bds_state(k), sig, &smlen, &data, 0, sshkey_xmss_params(k))) != 0) { r = SSH_ERR_INVALID_ARGUMENT; break; } } free(sig); return r; } int sshkey_xmss_update_state(const struct sshkey *k, sshkey_printfn *pr) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *b = NULL, *enc = NULL; u_int32_t idx = 0; unsigned char buf[4]; char *filename = NULL; char *statefile = NULL, *ostatefile = NULL, *nstatefile = NULL; int fd = -1; int ret = SSH_ERR_INVALID_ARGUMENT; if (state == NULL || !state->allow_update) return ret; if (state->maxidx) { /* no update since the number of signatures is limited */ ret = 0; goto done; } idx = PEEK_U32(k->xmss_sk); if (idx == state->idx) { /* no signature happened, no need to update */ ret = 0; goto done; } else if (idx != state->idx + 1) { PRINT("%s: more than one signature happened: idx %u state %u", __func__, idx, state->idx); goto done; } state->idx = idx; if ((filename = k->xmss_filename) == NULL) goto done; if (asprintf(&statefile, "%s.state", filename) < 0 || asprintf(&ostatefile, "%s.ostate", filename) < 0 || asprintf(&nstatefile, "%s.nstate", filename) < 0) { ret = SSH_ERR_ALLOC_FAIL; goto done; } unlink(nstatefile); if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto done; } if ((ret = sshkey_xmss_serialize_state(k, b)) != 0) { PRINT("%s: SERLIALIZE FAILED: %d", __func__, ret); goto done; } if ((ret = sshkey_xmss_encrypt_state(k, b, &enc)) != 0) { PRINT("%s: ENCRYPT FAILED: %d", __func__, ret); goto done; } if ((fd = open(nstatefile, O_CREAT|O_WRONLY|O_EXCL, 0600)) < 0) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: open new state file: %s", __func__, nstatefile); goto done; } POKE_U32(buf, sshbuf_len(enc)); if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: write new state file hdr: %s", __func__, nstatefile); close(fd); goto done; } if (atomicio(vwrite, fd, sshbuf_mutable_ptr(enc), sshbuf_len(enc)) != sshbuf_len(enc)) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: write new state file data: %s", __func__, nstatefile); close(fd); goto done; } if (fsync(fd) < 0) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: sync new state file: %s", __func__, nstatefile); close(fd); goto done; } if (close(fd) < 0) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: close new state file: %s", __func__, nstatefile); goto done; } if (state->have_state) { unlink(ostatefile); if (link(statefile, ostatefile)) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: backup state %s to %s", __func__, statefile, ostatefile); goto done; } } if (rename(nstatefile, statefile) < 0) { ret = SSH_ERR_SYSTEM_ERROR; PRINT("%s: rename %s to %s", __func__, nstatefile, statefile); goto done; } ret = 0; done: if (state->lockfd != -1) { close(state->lockfd); state->lockfd = -1; } if (nstatefile) unlink(nstatefile); free(statefile); free(ostatefile); free(nstatefile); sshbuf_free(b); sshbuf_free(enc); return ret; } int sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; treehash_inst *th; u_int32_t i, node; int r; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if (state->stack == NULL) return SSH_ERR_INVALID_ARGUMENT; state->stackoffset = state->bds.stackoffset; /* copy back */ if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 || (r = sshbuf_put_u32(b, state->idx)) != 0 || (r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 || (r = sshbuf_put_u32(b, state->stackoffset)) != 0 || (r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 || (r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 || (r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 || (r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 || (r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 || (r = sshbuf_put_u32(b, num_treehash(state))) != 0) return r; for (i = 0; i < num_treehash(state); i++) { th = &state->treehash[i]; node = th->node - state->th_nodes; if ((r = sshbuf_put_u32(b, th->h)) != 0 || (r = sshbuf_put_u32(b, th->next_idx)) != 0 || (r = sshbuf_put_u32(b, th->stackusage)) != 0 || (r = sshbuf_put_u8(b, th->completed)) != 0 || (r = sshbuf_put_u32(b, node)) != 0) return r; } return 0; } int sshkey_xmss_serialize_state_opt(const struct sshkey *k, struct sshbuf *b, enum sshkey_serialize_rep opts) { struct ssh_xmss_state *state = k->xmss_state; int r = SSH_ERR_INVALID_ARGUMENT; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_put_u8(b, opts)) != 0) return r; switch (opts) { case SSHKEY_SERIALIZE_STATE: r = sshkey_xmss_serialize_state(k, b); break; case SSHKEY_SERIALIZE_FULL: if ((r = sshkey_xmss_serialize_enc_key(k, b)) != 0) break; r = sshkey_xmss_serialize_state(k, b); break; case SSHKEY_SERIALIZE_DEFAULT: r = 0; break; default: r = SSH_ERR_INVALID_ARGUMENT; break; } return r; } int sshkey_xmss_deserialize_state(struct sshkey *k, struct sshbuf *b) { struct ssh_xmss_state *state = k->xmss_state; treehash_inst *th; u_int32_t i, lh, node; size_t ls, lsl, la, lk, ln, lr; char *magic; int r; if (state == NULL) return SSH_ERR_INVALID_ARGUMENT; if (k->xmss_sk == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((state->treehash = calloc(num_treehash(state), sizeof(treehash_inst))) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_get_cstring(b, &magic, NULL)) != 0 || (r = sshbuf_get_u32(b, &state->idx)) != 0 || (r = sshbuf_get_string(b, &state->stack, &ls)) != 0 || (r = sshbuf_get_u32(b, &state->stackoffset)) != 0 || (r = sshbuf_get_string(b, &state->stacklevels, &lsl)) != 0 || (r = sshbuf_get_string(b, &state->auth, &la)) != 0 || (r = sshbuf_get_string(b, &state->keep, &lk)) != 0 || (r = sshbuf_get_string(b, &state->th_nodes, &ln)) != 0 || (r = sshbuf_get_string(b, &state->retain, &lr)) != 0 || (r = sshbuf_get_u32(b, &lh)) != 0) return r; if (strcmp(magic, SSH_XMSS_K2_MAGIC) != 0) return SSH_ERR_INVALID_ARGUMENT; /* XXX check stackoffset */ if (ls != num_stack(state) || lsl != num_stacklevels(state) || la != num_auth(state) || lk != num_keep(state) || ln != num_th_nodes(state) || lr != num_retain(state) || lh != num_treehash(state)) return SSH_ERR_INVALID_ARGUMENT; for (i = 0; i < num_treehash(state); i++) { th = &state->treehash[i]; if ((r = sshbuf_get_u32(b, &th->h)) != 0 || (r = sshbuf_get_u32(b, &th->next_idx)) != 0 || (r = sshbuf_get_u32(b, &th->stackusage)) != 0 || (r = sshbuf_get_u8(b, &th->completed)) != 0 || (r = sshbuf_get_u32(b, &node)) != 0) return r; if (node < num_th_nodes(state)) th->node = &state->th_nodes[node]; } POKE_U32(k->xmss_sk, state->idx); xmss_set_bds_state(&state->bds, state->stack, state->stackoffset, state->stacklevels, state->auth, state->keep, state->treehash, state->retain, 0); return 0; } int sshkey_xmss_deserialize_state_opt(struct sshkey *k, struct sshbuf *b) { enum sshkey_serialize_rep opts; u_char have_state; int r; if ((r = sshbuf_get_u8(b, &have_state)) != 0) return r; opts = have_state; switch (opts) { case SSHKEY_SERIALIZE_DEFAULT: r = 0; break; case SSHKEY_SERIALIZE_STATE: if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) return r; break; case SSHKEY_SERIALIZE_FULL: if ((r = sshkey_xmss_deserialize_enc_key(k, b)) != 0 || (r = sshkey_xmss_deserialize_state(k, b)) != 0) return r; break; default: r = SSH_ERR_INVALID_FORMAT; break; } return r; } int sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b, struct sshbuf **retp) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL; struct sshcipher_ctx *ciphercontext = NULL; const struct sshcipher *cipher; u_char *cp, *key, *iv = NULL; size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INTERNAL_ERROR; if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { r = SSH_ERR_INTERNAL_ERROR; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if (state->enc_keyiv_len != keylen + ivlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } key = state->enc_keyiv; if ((encrypted = sshbuf_new()) == NULL || (encoded = sshbuf_new()) == NULL || (padded = sshbuf_new()) == NULL || (iv = malloc(ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* replace first 4 bytes of IV with index to ensure uniqueness */ memcpy(iv, key + keylen, ivlen); POKE_U32(iv, state->idx); if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 || (r = sshbuf_put_u32(encoded, state->idx)) != 0) goto out; /* padded state will be encrypted */ if ((r = sshbuf_putb(padded, b)) != 0) goto out; i = 0; while (sshbuf_len(padded) % blocksize) { if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0) goto out; } encrypted_len = sshbuf_len(padded); /* header including the length of state is used as AAD */ if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0) goto out; aadlen = sshbuf_len(encoded); /* concat header and state */ if ((r = sshbuf_putb(encoded, padded)) != 0) goto out; /* reserve space for encryption of encoded data plus auth tag */ /* encrypt at offset addlen */ if ((r = sshbuf_reserve(encrypted, encrypted_len + aadlen + authlen, &cp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, iv, ivlen, 1)) != 0 || (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), encrypted_len, aadlen, authlen)) != 0) goto out; /* success */ r = 0; out: if (retp != NULL) { *retp = encrypted; encrypted = NULL; } sshbuf_free(padded); sshbuf_free(encoded); sshbuf_free(encrypted); cipher_free(ciphercontext); free(iv); return r; } int sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded, struct sshbuf **retp) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *copy = NULL, *decrypted = NULL; struct sshcipher_ctx *ciphercontext = NULL; const struct sshcipher *cipher = NULL; u_char *key, *iv = NULL, *dp; size_t keylen, ivlen, authlen, aadlen; u_int blocksize, encrypted_len, index; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INTERNAL_ERROR; if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { r = SSH_ERR_INVALID_FORMAT; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if (state->enc_keyiv_len != keylen + ivlen) { r = SSH_ERR_INTERNAL_ERROR; goto out; } key = state->enc_keyiv; if ((copy = sshbuf_fromb(encoded)) == NULL || (decrypted = sshbuf_new()) == NULL || (iv = malloc(ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* check magic */ if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) || memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* parse public portion */ if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 || (r = sshbuf_get_u32(encoded, &index)) != 0 || (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0) goto out; /* check size of encrypted key blob */ if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* check that an appropriate amount of auth data is present */ if (sshbuf_len(encoded) < encrypted_len + authlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } aadlen = sshbuf_len(copy) - sshbuf_len(encoded); /* replace first 4 bytes of IV with index to ensure uniqueness */ memcpy(iv, key + keylen, ivlen); POKE_U32(iv, index); /* decrypt private state of key */ if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, iv, ivlen, 0)) != 0 || (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), encrypted_len, aadlen, authlen)) != 0) goto out; /* there should be no trailing data */ if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0) goto out; if (sshbuf_len(encoded) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* remove AAD */ if ((r = sshbuf_consume(decrypted, aadlen)) != 0) goto out; /* XXX encrypted includes unchecked padding */ /* success */ r = 0; if (retp != NULL) { *retp = decrypted; decrypted = NULL; } out: cipher_free(ciphercontext); sshbuf_free(copy); sshbuf_free(decrypted); free(iv); return r; } u_int32_t sshkey_xmss_signatures_left(const struct sshkey *k) { struct ssh_xmss_state *state = k->xmss_state; u_int32_t idx; if (sshkey_type_plain(k->type) == KEY_XMSS && state && state->maxidx) { idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx; if (idx < state->maxidx) return state->maxidx - idx; } return 0; } int sshkey_xmss_enable_maxsign(struct sshkey *k, u_int32_t maxsign) { struct ssh_xmss_state *state = k->xmss_state; if (sshkey_type_plain(k->type) != KEY_XMSS) return SSH_ERR_INVALID_ARGUMENT; if (maxsign == 0) return 0; if (state->idx + maxsign < state->idx) return SSH_ERR_INVALID_ARGUMENT; state->maxidx = state->idx + maxsign; return 0; } #endif /* WITH_XMSS */
Upload File
Create Folder