1323124Sdes/* $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> 21295367Sdes#include <limits.h> 22261287Sdes 23261287Sdes#include "crypto_api.h" 24261287Sdes 25261287Sdes#include <string.h> 26261287Sdes#include <stdarg.h> 27261287Sdes 28261287Sdes#include "log.h" 29295367Sdes#include "sshbuf.h" 30295367Sdes#define SSHKEY_INTERNAL 31295367Sdes#include "sshkey.h" 32295367Sdes#include "ssherr.h" 33261287Sdes#include "ssh.h" 34261287Sdes 35261287Sdesint 36295367Sdesssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 37295367Sdes const u_char *data, size_t datalen, u_int compat) 38261287Sdes{ 39295367Sdes u_char *sig = NULL; 40295367Sdes size_t slen = 0, len; 41261287Sdes unsigned long long smlen; 42295367Sdes int r, ret; 43295367Sdes struct sshbuf *b = NULL; 44261287Sdes 45295367Sdes if (lenp != NULL) 46295367Sdes *lenp = 0; 47295367Sdes if (sigp != NULL) 48295367Sdes *sigp = NULL; 49264377Sdes 50295367Sdes if (key == NULL || 51295367Sdes sshkey_type_plain(key->type) != KEY_ED25519 || 52295367Sdes key->ed25519_sk == NULL || 53295367Sdes datalen >= INT_MAX - crypto_sign_ed25519_BYTES) 54295367Sdes return SSH_ERR_INVALID_ARGUMENT; 55261287Sdes smlen = slen = datalen + crypto_sign_ed25519_BYTES; 56295367Sdes if ((sig = malloc(slen)) == NULL) 57295367Sdes return SSH_ERR_ALLOC_FAIL; 58261287Sdes 59261287Sdes if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, 60261287Sdes key->ed25519_sk)) != 0 || smlen <= datalen) { 61295367Sdes r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ 62295367Sdes goto out; 63261287Sdes } 64261287Sdes /* encode signature */ 65295367Sdes if ((b = sshbuf_new()) == NULL) { 66295367Sdes r = SSH_ERR_ALLOC_FAIL; 67295367Sdes goto out; 68295367Sdes } 69295367Sdes if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || 70295367Sdes (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) 71295367Sdes goto out; 72295367Sdes len = sshbuf_len(b); 73295367Sdes if (sigp != NULL) { 74295367Sdes if ((*sigp = malloc(len)) == NULL) { 75295367Sdes r = SSH_ERR_ALLOC_FAIL; 76295367Sdes goto out; 77295367Sdes } 78295367Sdes memcpy(*sigp, sshbuf_ptr(b), len); 79295367Sdes } 80261287Sdes if (lenp != NULL) 81261287Sdes *lenp = len; 82295367Sdes /* success */ 83295367Sdes r = 0; 84295367Sdes out: 85295367Sdes sshbuf_free(b); 86295367Sdes if (sig != NULL) { 87295367Sdes explicit_bzero(sig, slen); 88295367Sdes free(sig); 89261287Sdes } 90261287Sdes 91295367Sdes return r; 92261287Sdes} 93261287Sdes 94261287Sdesint 95295367Sdesssh_ed25519_verify(const struct sshkey *key, 96295367Sdes const u_char *signature, size_t signaturelen, 97295367Sdes const u_char *data, size_t datalen, u_int compat) 98261287Sdes{ 99295367Sdes struct sshbuf *b = NULL; 100295367Sdes char *ktype = NULL; 101295367Sdes const u_char *sigblob; 102295367Sdes u_char *sm = NULL, *m = NULL; 103295367Sdes size_t len; 104295367Sdes unsigned long long smlen = 0, mlen = 0; 105295367Sdes int r, ret; 106261287Sdes 107295367Sdes if (key == NULL || 108295367Sdes sshkey_type_plain(key->type) != KEY_ED25519 || 109295367Sdes key->ed25519_pk == NULL || 110323124Sdes datalen >= INT_MAX - crypto_sign_ed25519_BYTES || 111323124Sdes signature == NULL || signaturelen == 0) 112295367Sdes return SSH_ERR_INVALID_ARGUMENT; 113295367Sdes 114295367Sdes if ((b = sshbuf_from(signature, signaturelen)) == NULL) 115295367Sdes return SSH_ERR_ALLOC_FAIL; 116295367Sdes if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || 117295367Sdes (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) 118295367Sdes goto out; 119261287Sdes if (strcmp("ssh-ed25519", ktype) != 0) { 120295367Sdes r = SSH_ERR_KEY_TYPE_MISMATCH; 121295367Sdes goto out; 122261287Sdes } 123295367Sdes if (sshbuf_len(b) != 0) { 124295367Sdes r = SSH_ERR_UNEXPECTED_TRAILING_DATA; 125295367Sdes goto out; 126261287Sdes } 127261287Sdes if (len > crypto_sign_ed25519_BYTES) { 128295367Sdes r = SSH_ERR_INVALID_FORMAT; 129295367Sdes goto out; 130261287Sdes } 131295367Sdes if (datalen >= SIZE_MAX - len) { 132295367Sdes r = SSH_ERR_INVALID_ARGUMENT; 133295367Sdes goto out; 134295367Sdes } 135261287Sdes smlen = len + datalen; 136295367Sdes mlen = smlen; 137295367Sdes if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { 138295367Sdes r = SSH_ERR_ALLOC_FAIL; 139295367Sdes goto out; 140295367Sdes } 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 } 148295367Sdes if (ret != 0 || mlen != datalen) { 149295367Sdes r = SSH_ERR_SIGNATURE_INVALID; 150295367Sdes goto out; 151261287Sdes } 152261287Sdes /* XXX compare 'm' and 'data' ? */ 153295367Sdes /* success */ 154295367Sdes r = 0; 155295367Sdes out: 156295367Sdes if (sm != NULL) { 157295367Sdes explicit_bzero(sm, smlen); 158295367Sdes free(sm); 159295367Sdes } 160295367Sdes if (m != NULL) { 161295367Sdes explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ 162295367Sdes free(m); 163295367Sdes } 164295367Sdes sshbuf_free(b); 165295367Sdes free(ktype); 166295367Sdes return r; 167261287Sdes} 168