Annotation of src/usr.bin/ssh/ssh-xmss.c, Revision 1.1
1.1 ! markus 1: /* $OpenBSD: $*/
! 2: /*
! 3: * Copyright (c) 2017 Stefan-Lukas Gazdag.
! 4: * Copyright (c) 2017 Markus Friedl.
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18: #define SSHKEY_INTERNAL
! 19: #include <sys/types.h>
! 20: #include <limits.h>
! 21:
! 22: #include <string.h>
! 23: #include <stdarg.h>
! 24: #include <unistd.h>
! 25:
! 26: #include "log.h"
! 27: #include "sshbuf.h"
! 28: #include "sshkey.h"
! 29: #include "sshkey-xmss.h"
! 30: #include "ssherr.h"
! 31: #include "ssh.h"
! 32:
! 33: #include "xmss_fast.h"
! 34:
! 35: int
! 36: ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
! 37: const u_char *data, size_t datalen, u_int compat)
! 38: {
! 39: u_char *sig = NULL;
! 40: size_t slen = 0, len = 0, required_siglen;
! 41: unsigned long long smlen;
! 42: int r, ret;
! 43: struct sshbuf *b = NULL;
! 44:
! 45: if (lenp != NULL)
! 46: *lenp = 0;
! 47: if (sigp != NULL)
! 48: *sigp = NULL;
! 49:
! 50: if (key == NULL ||
! 51: sshkey_type_plain(key->type) != KEY_XMSS ||
! 52: key->xmss_sk == NULL ||
! 53: sshkey_xmss_params(key) == NULL)
! 54: return SSH_ERR_INVALID_ARGUMENT;
! 55: if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
! 56: return r;
! 57: if (datalen >= INT_MAX - required_siglen)
! 58: return SSH_ERR_INVALID_ARGUMENT;
! 59: smlen = slen = datalen + required_siglen;
! 60: if ((sig = malloc(slen)) == NULL)
! 61: return SSH_ERR_ALLOC_FAIL;
! 62: if ((r = sshkey_xmss_get_state(key, error)) != 0)
! 63: goto out;
! 64: if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
! 65: data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
! 66: r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
! 67: goto out;
! 68: }
! 69: /* encode signature */
! 70: if ((b = sshbuf_new()) == NULL) {
! 71: r = SSH_ERR_ALLOC_FAIL;
! 72: goto out;
! 73: }
! 74: if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
! 75: (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
! 76: goto out;
! 77: len = sshbuf_len(b);
! 78: if (sigp != NULL) {
! 79: if ((*sigp = malloc(len)) == NULL) {
! 80: r = SSH_ERR_ALLOC_FAIL;
! 81: goto out;
! 82: }
! 83: memcpy(*sigp, sshbuf_ptr(b), len);
! 84: }
! 85: if (lenp != NULL)
! 86: *lenp = len;
! 87: /* success */
! 88: r = 0;
! 89: out:
! 90: if ((ret = sshkey_xmss_update_state(key, error)) != 0) {
! 91: /* discard signature since we cannot update the state */
! 92: if (r == 0 && sigp != NULL && *sigp != NULL) {
! 93: explicit_bzero(*sigp, len);
! 94: free(*sigp);
! 95: }
! 96: if (sigp != NULL)
! 97: *sigp = NULL;
! 98: if (lenp != NULL)
! 99: *lenp = 0;
! 100: r = ret;
! 101: }
! 102: sshbuf_free(b);
! 103: if (sig != NULL) {
! 104: explicit_bzero(sig, slen);
! 105: free(sig);
! 106: }
! 107:
! 108: return r;
! 109: }
! 110:
! 111: int
! 112: ssh_xmss_verify(const struct sshkey *key,
! 113: const u_char *signature, size_t signaturelen,
! 114: const u_char *data, size_t datalen, u_int compat)
! 115: {
! 116: struct sshbuf *b = NULL;
! 117: char *ktype = NULL;
! 118: const u_char *sigblob;
! 119: u_char *sm = NULL, *m = NULL;
! 120: size_t len, required_siglen;
! 121: unsigned long long smlen = 0, mlen = 0;
! 122: int r, ret;
! 123:
! 124: if (key == NULL ||
! 125: sshkey_type_plain(key->type) != KEY_XMSS ||
! 126: key->xmss_pk == NULL ||
! 127: sshkey_xmss_params(key) == NULL ||
! 128: signature == NULL || signaturelen == 0)
! 129: return SSH_ERR_INVALID_ARGUMENT;
! 130: if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
! 131: return r;
! 132: if (datalen >= INT_MAX - required_siglen)
! 133: return SSH_ERR_INVALID_ARGUMENT;
! 134:
! 135: if ((b = sshbuf_from(signature, signaturelen)) == NULL)
! 136: return SSH_ERR_ALLOC_FAIL;
! 137: if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
! 138: (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
! 139: goto out;
! 140: if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
! 141: r = SSH_ERR_KEY_TYPE_MISMATCH;
! 142: goto out;
! 143: }
! 144: if (sshbuf_len(b) != 0) {
! 145: r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
! 146: goto out;
! 147: }
! 148: if (len != required_siglen) {
! 149: r = SSH_ERR_INVALID_FORMAT;
! 150: goto out;
! 151: }
! 152: if (datalen >= SIZE_MAX - len) {
! 153: r = SSH_ERR_INVALID_ARGUMENT;
! 154: goto out;
! 155: }
! 156: smlen = len + datalen;
! 157: mlen = smlen;
! 158: if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
! 159: r = SSH_ERR_ALLOC_FAIL;
! 160: goto out;
! 161: }
! 162: memcpy(sm, sigblob, len);
! 163: memcpy(sm+len, data, datalen);
! 164: if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
! 165: key->xmss_pk, sshkey_xmss_params(key))) != 0) {
! 166: debug2("%s: crypto_sign_xmss_open failed: %d",
! 167: __func__, ret);
! 168: }
! 169: if (ret != 0 || mlen != datalen) {
! 170: r = SSH_ERR_SIGNATURE_INVALID;
! 171: goto out;
! 172: }
! 173: /* XXX compare 'm' and 'data' ? */
! 174: /* success */
! 175: r = 0;
! 176: out:
! 177: if (sm != NULL) {
! 178: explicit_bzero(sm, smlen);
! 179: free(sm);
! 180: }
! 181: if (m != NULL) {
! 182: explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */
! 183: free(m);
! 184: }
! 185: sshbuf_free(b);
! 186: free(ktype);
! 187: return r;
! 188: }