1 /* $NetBSD: ssh-ed25519-sk.c,v 1.3 2020/05/28 17:05:49 christos Exp $ */ 2 /* $OpenBSD: ssh-ed25519-sk.c,v 1.5 2020/02/26 13:40:09 jsg Exp $ */ 3 /* 4 * Copyright (c) 2019 Markus Friedl. All rights reserved. 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 #include "includes.h" 19 __RCSID("$NetBSD: ssh-ed25519-sk.c,v 1.3 2020/05/28 17:05:49 christos Exp $"); 20 21 /* #define DEBUG_SK 1 */ 22 23 #define SSHKEY_INTERNAL 24 #include <sys/types.h> 25 #include <limits.h> 26 27 #include "crypto_api.h" 28 29 #include <string.h> 30 #include <stdarg.h> 31 32 #include "log.h" 33 #include "sshbuf.h" 34 #include "sshkey.h" 35 #include "ssherr.h" 36 #include "ssh.h" 37 #include "digest.h" 38 39 int 40 ssh_ed25519_sk_verify(const struct sshkey *key, 41 const u_char *signature, size_t signaturelen, 42 const u_char *data, size_t datalen, u_int compat, 43 struct sshkey_sig_details **detailsp) 44 { 45 struct sshbuf *b = NULL; 46 struct sshbuf *encoded = NULL; 47 char *ktype = NULL; 48 const u_char *sigblob; 49 const u_char *sm; 50 u_char *m = NULL; 51 u_char apphash[32]; 52 u_char msghash[32]; 53 u_char sig_flags; 54 u_int sig_counter; 55 size_t len; 56 unsigned long long smlen = 0, mlen = 0; 57 int r = SSH_ERR_INTERNAL_ERROR; 58 int ret; 59 struct sshkey_sig_details *details = NULL; 60 61 if (detailsp != NULL) 62 *detailsp = NULL; 63 64 if (key == NULL || 65 sshkey_type_plain(key->type) != KEY_ED25519_SK || 66 key->ed25519_pk == NULL || 67 signature == NULL || signaturelen == 0) 68 return SSH_ERR_INVALID_ARGUMENT; 69 70 if ((b = sshbuf_from(signature, signaturelen)) == NULL) 71 return SSH_ERR_ALLOC_FAIL; 72 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || 73 sshbuf_get_string_direct(b, &sigblob, &len) != 0 || 74 sshbuf_get_u8(b, &sig_flags) != 0 || 75 sshbuf_get_u32(b, &sig_counter) != 0) { 76 r = SSH_ERR_INVALID_FORMAT; 77 goto out; 78 } 79 #ifdef DEBUG_SK 80 fprintf(stderr, "%s: data:\n", __func__); 81 /* sshbuf_dump_data(data, datalen, stderr); */ 82 fprintf(stderr, "%s: sigblob:\n", __func__); 83 sshbuf_dump_data(sigblob, len, stderr); 84 fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n", 85 __func__, sig_flags, sig_counter); 86 #endif 87 if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) { 88 r = SSH_ERR_KEY_TYPE_MISMATCH; 89 goto out; 90 } 91 if (sshbuf_len(b) != 0) { 92 r = SSH_ERR_UNEXPECTED_TRAILING_DATA; 93 goto out; 94 } 95 if (len > crypto_sign_ed25519_BYTES) { 96 r = SSH_ERR_INVALID_FORMAT; 97 goto out; 98 } 99 if (ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application, 100 strlen(key->sk_application), apphash, sizeof(apphash)) != 0 || 101 ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen, 102 msghash, sizeof(msghash)) != 0) { 103 r = SSH_ERR_INVALID_ARGUMENT; 104 goto out; 105 } 106 #ifdef DEBUG_SK 107 fprintf(stderr, "%s: hashed application:\n", __func__); 108 sshbuf_dump_data(apphash, sizeof(apphash), stderr); 109 fprintf(stderr, "%s: hashed message:\n", __func__); 110 sshbuf_dump_data(msghash, sizeof(msghash), stderr); 111 #endif 112 if ((details = calloc(1, sizeof(*details))) == NULL) { 113 r = SSH_ERR_ALLOC_FAIL; 114 goto out; 115 } 116 details->sk_counter = sig_counter; 117 details->sk_flags = sig_flags; 118 if ((encoded = sshbuf_new()) == NULL) { 119 r = SSH_ERR_ALLOC_FAIL; 120 goto out; 121 } 122 if (sshbuf_put(encoded, sigblob, len) != 0 || 123 sshbuf_put(encoded, apphash, sizeof(apphash)) != 0 || 124 sshbuf_put_u8(encoded, sig_flags) != 0 || 125 sshbuf_put_u32(encoded, sig_counter) != 0 || 126 sshbuf_put(encoded, msghash, sizeof(msghash)) != 0) { 127 r = SSH_ERR_ALLOC_FAIL; 128 goto out; 129 } 130 #ifdef DEBUG_SK 131 fprintf(stderr, "%s: signed buf:\n", __func__); 132 sshbuf_dump(encoded, stderr); 133 #endif 134 sm = sshbuf_ptr(encoded); 135 smlen = sshbuf_len(encoded); 136 mlen = smlen; 137 if ((m = malloc(smlen)) == NULL) { 138 r = SSH_ERR_ALLOC_FAIL; 139 goto out; 140 } 141 if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, 142 key->ed25519_pk)) != 0) { 143 debug2("%s: crypto_sign_ed25519_open failed: %d", 144 __func__, ret); 145 } 146 if (ret != 0 || mlen != smlen - len) { 147 r = SSH_ERR_SIGNATURE_INVALID; 148 goto out; 149 } 150 /* XXX compare 'm' and 'sm + len' ? */ 151 /* success */ 152 r = 0; 153 if (detailsp != NULL) { 154 *detailsp = details; 155 details = NULL; 156 } 157 out: 158 if (m != NULL) 159 freezero(m, smlen); /* NB mlen may be invalid if r != 0 */ 160 sshkey_sig_details_free(details); 161 sshbuf_free(b); 162 sshbuf_free(encoded); 163 free(ktype); 164 return r; 165 } 166