1323129Sdes/* $OpenBSD: ssh-ed25519.c,v 1.7 2016/04/21 06:08:02 djm Exp $ */ 2261287Sdes/* 3261287Sdes * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> 4261287Sdes * 5261287Sdes * Permission to use, copy, modify, and distribute this software for any 6261287Sdes * purpose with or without fee is hereby granted, provided that the above 7261287Sdes * copyright notice and this permission notice appear in all copies. 8261287Sdes * 9261287Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10261287Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11261287Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12261287Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13261287Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14261287Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15261287Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16261287Sdes */ 17261287Sdes 18261287Sdes#include "includes.h" 19261287Sdes 20261287Sdes#include <sys/types.h> 21294328Sdes#include <limits.h> 22261287Sdes 23261287Sdes#include "crypto_api.h" 24261287Sdes 25261287Sdes#include <string.h> 26261287Sdes#include <stdarg.h> 27261287Sdes 28261287Sdes#include "log.h" 29294332Sdes#include "sshbuf.h" 30294328Sdes#define SSHKEY_INTERNAL 31294328Sdes#include "sshkey.h" 32294328Sdes#include "ssherr.h" 33261287Sdes#include "ssh.h" 34261287Sdes 35261287Sdesint 36294328Sdesssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 37294328Sdes const u_char *data, size_t datalen, u_int compat) 38261287Sdes{ 39294328Sdes u_char *sig = NULL; 40294328Sdes size_t slen = 0, len; 41261287Sdes unsigned long long smlen; 42294328Sdes int r, ret; 43294328Sdes struct sshbuf *b = NULL; 44261287Sdes 45294328Sdes if (lenp != NULL) 46294328Sdes *lenp = 0; 47294328Sdes if (sigp != NULL) 48294328Sdes *sigp = NULL; 49263712Sdes 50294328Sdes if (key == NULL || 51294328Sdes sshkey_type_plain(key->type) != KEY_ED25519 || 52294328Sdes key->ed25519_sk == NULL || 53294328Sdes datalen >= INT_MAX - crypto_sign_ed25519_BYTES) 54294328Sdes return SSH_ERR_INVALID_ARGUMENT; 55261287Sdes smlen = slen = datalen + crypto_sign_ed25519_BYTES; 56294328Sdes if ((sig = malloc(slen)) == NULL) 57294328Sdes return SSH_ERR_ALLOC_FAIL; 58261287Sdes 59261287Sdes if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, 60261287Sdes key->ed25519_sk)) != 0 || smlen <= datalen) { 61294328Sdes r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ 62294328Sdes goto out; 63261287Sdes } 64261287Sdes /* encode signature */ 65294328Sdes if ((b = sshbuf_new()) == NULL) { 66294328Sdes r = SSH_ERR_ALLOC_FAIL; 67294328Sdes goto out; 68294328Sdes } 69294328Sdes if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || 70294328Sdes (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) 71294328Sdes goto out; 72294328Sdes len = sshbuf_len(b); 73294328Sdes if (sigp != NULL) { 74294328Sdes if ((*sigp = malloc(len)) == NULL) { 75294328Sdes r = SSH_ERR_ALLOC_FAIL; 76294328Sdes goto out; 77294328Sdes } 78294328Sdes memcpy(*sigp, sshbuf_ptr(b), len); 79294328Sdes } 80261287Sdes if (lenp != NULL) 81261287Sdes *lenp = len; 82294328Sdes /* success */ 83294328Sdes r = 0; 84294328Sdes out: 85294328Sdes sshbuf_free(b); 86294328Sdes if (sig != NULL) { 87294328Sdes explicit_bzero(sig, slen); 88294328Sdes free(sig); 89261287Sdes } 90261287Sdes 91294328Sdes return r; 92261287Sdes} 93261287Sdes 94261287Sdesint 95294328Sdesssh_ed25519_verify(const struct sshkey *key, 96294328Sdes const u_char *signature, size_t signaturelen, 97294328Sdes const u_char *data, size_t datalen, u_int compat) 98261287Sdes{ 99294328Sdes struct sshbuf *b = NULL; 100294328Sdes char *ktype = NULL; 101294328Sdes const u_char *sigblob; 102294328Sdes u_char *sm = NULL, *m = NULL; 103294328Sdes size_t len; 104294328Sdes unsigned long long smlen = 0, mlen = 0; 105294328Sdes int r, ret; 106261287Sdes 107294328Sdes if (key == NULL || 108294328Sdes sshkey_type_plain(key->type) != KEY_ED25519 || 109294328Sdes key->ed25519_pk == NULL || 110323129Sdes datalen >= INT_MAX - crypto_sign_ed25519_BYTES || 111323129Sdes signature == NULL || signaturelen == 0) 112294328Sdes return SSH_ERR_INVALID_ARGUMENT; 113294328Sdes 114294328Sdes if ((b = sshbuf_from(signature, signaturelen)) == NULL) 115294328Sdes return SSH_ERR_ALLOC_FAIL; 116294328Sdes if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || 117294328Sdes (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) 118294328Sdes goto out; 119261287Sdes if (strcmp("ssh-ed25519", ktype) != 0) { 120294328Sdes r = SSH_ERR_KEY_TYPE_MISMATCH; 121294328Sdes goto out; 122261287Sdes } 123294328Sdes if (sshbuf_len(b) != 0) { 124294328Sdes r = SSH_ERR_UNEXPECTED_TRAILING_DATA; 125294328Sdes goto out; 126261287Sdes } 127261287Sdes if (len > crypto_sign_ed25519_BYTES) { 128294328Sdes r = SSH_ERR_INVALID_FORMAT; 129294328Sdes goto out; 130261287Sdes } 131294332Sdes if (datalen >= SIZE_MAX - len) { 132294332Sdes r = SSH_ERR_INVALID_ARGUMENT; 133294332Sdes goto out; 134294332Sdes } 135261287Sdes smlen = len + datalen; 136294328Sdes mlen = smlen; 137294332Sdes if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { 138294328Sdes r = SSH_ERR_ALLOC_FAIL; 139294328Sdes goto out; 140294328Sdes } 141261287Sdes memcpy(sm, sigblob, len); 142261287Sdes memcpy(sm+len, data, datalen); 143261287Sdes if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, 144261287Sdes key->ed25519_pk)) != 0) { 145261287Sdes debug2("%s: crypto_sign_ed25519_open failed: %d", 146261287Sdes __func__, ret); 147261287Sdes } 148294328Sdes if (ret != 0 || mlen != datalen) { 149294328Sdes r = SSH_ERR_SIGNATURE_INVALID; 150294328Sdes goto out; 151261287Sdes } 152261287Sdes /* XXX compare 'm' and 'data' ? */ 153294328Sdes /* success */ 154294328Sdes r = 0; 155294328Sdes out: 156294328Sdes if (sm != NULL) { 157294328Sdes explicit_bzero(sm, smlen); 158294328Sdes free(sm); 159294328Sdes } 160294328Sdes if (m != NULL) { 161294328Sdes explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ 162294328Sdes free(m); 163294328Sdes } 164294328Sdes sshbuf_free(b); 165294328Sdes free(ktype); 166294328Sdes return r; 167294328Sdes} 168