blob: 3559246578818c5e822831e8c3463580dcc5d70a [file] [log] [blame]
djm@openbsd.org02bb0762019-10-31 21:15:14 +00001/* $OpenBSD: ssh-ecdsa-sk.c,v 1.1 2019/10/31 21:15:14 djm Exp $ */
2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Copyright (c) 2010 Damien Miller. All rights reserved.
5 * Copyright (c) 2019 Google Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* #define DEBUG_SK 1 */
29
30#include "includes.h"
31
Damien Miller764d51e2019-11-01 13:34:49 +110032#ifdef ENABLE_SK
33
djm@openbsd.org02bb0762019-10-31 21:15:14 +000034#include <sys/types.h>
35
36#include <openssl/bn.h>
37#include <openssl/ec.h>
38#include <openssl/ecdsa.h>
39#include <openssl/evp.h>
40
41#include <string.h>
42#include <stdio.h> /* needed for DEBUG_SK only */
43
44#include "sshbuf.h"
45#include "ssherr.h"
46#include "digest.h"
47#define SSHKEY_INTERNAL
48#include "sshkey.h"
49
50/* ARGSUSED */
51int
52ssh_ecdsa_sk_verify(const struct sshkey *key,
53 const u_char *signature, size_t signaturelen,
54 const u_char *data, size_t datalen, u_int compat)
55{
56 ECDSA_SIG *sig = NULL;
57 BIGNUM *sig_r = NULL, *sig_s = NULL;
58 u_char sig_flags;
59 u_char msghash[32], apphash[32], sighash[32];
60 u_int sig_counter;
61 int ret = SSH_ERR_INTERNAL_ERROR;
62 struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL;
63 char *ktype = NULL;
64#ifdef DEBUG_SK
65 char *tmp = NULL;
66#endif
67
68 if (key == NULL || key->ecdsa == NULL ||
69 sshkey_type_plain(key->type) != KEY_ECDSA_SK ||
70 signature == NULL || signaturelen == 0)
71 return SSH_ERR_INVALID_ARGUMENT;
72
73 if (key->ecdsa_nid != NID_X9_62_prime256v1)
74 return SSH_ERR_INTERNAL_ERROR;
75
76 /* fetch signature */
77 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
78 return SSH_ERR_ALLOC_FAIL;
79 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
80 sshbuf_froms(b, &sigbuf) != 0) {
81 ret = SSH_ERR_INVALID_FORMAT;
82 goto out;
83 }
84 if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
85 ret = SSH_ERR_KEY_TYPE_MISMATCH;
86 goto out;
87 }
88 if (sshbuf_len(b) != 0) {
89 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
90 goto out;
91 }
92
93 /* parse signature */
94 if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 ||
95 sshbuf_get_bignum2(sigbuf, &sig_s) != 0 ||
96 sshbuf_get_u8(sigbuf, &sig_flags) != 0 ||
97 sshbuf_get_u32(sigbuf, &sig_counter) != 0) {
98 ret = SSH_ERR_INVALID_FORMAT;
99 goto out;
100 }
101 if ((sig = ECDSA_SIG_new()) == NULL) {
102 ret = SSH_ERR_ALLOC_FAIL;
103 goto out;
104 }
105 if (!ECDSA_SIG_set0(sig, sig_r, sig_s)) {
106 ret = SSH_ERR_LIBCRYPTO_ERROR;
107 goto out;
108 }
109#ifdef DEBUG_SK
110 fprintf(stderr, "%s: sig_r: %s\n", __func__, (tmp = BN_bn2hex(sig_r)));
111 free(tmp);
112 fprintf(stderr, "%s: sig_s: %s\n", __func__, (tmp = BN_bn2hex(sig_s)));
113 free(tmp);
114 fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
115 __func__, sig_flags, sig_counter);
116#endif
117 sig_r = sig_s = NULL; /* transferred */
118
119 if (sshbuf_len(sigbuf) != 0) {
120 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
121 goto out;
122 }
123
124 /* Reconstruct data that was supposedly signed */
125 if ((original_signed = sshbuf_new()) == NULL)
126 return SSH_ERR_ALLOC_FAIL;
127 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,
128 msghash, sizeof(msghash))) != 0)
129 goto out;
130 /* Application value is hashed before signature */
131 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application,
132 strlen(key->sk_application), apphash, sizeof(apphash))) != 0)
133 goto out;
134#ifdef DEBUG_SK
135 fprintf(stderr, "%s: hashed message:\n", __func__);
136 sshbuf_dump_data(msghash, sizeof(msghash), stderr);
137#endif
138 if ((ret = sshbuf_put(original_signed,
139 apphash, sizeof(apphash))) != 0 ||
140 (ret = sshbuf_put_u8(original_signed, sig_flags)) != 0 ||
141 (ret = sshbuf_put_u32(original_signed, sig_counter)) != 0 ||
142 (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0)
143 goto out;
144 /* Signature is over H(original_signed) */
145 if ((ret = ssh_digest_buffer(SSH_DIGEST_SHA256, original_signed,
146 sighash, sizeof(sighash))) != 0)
147 goto out;
148#ifdef DEBUG_SK
149 fprintf(stderr, "%s: signed buf:\n", __func__);
150 sshbuf_dump(original_signed, stderr);
151 fprintf(stderr, "%s: signed hash:\n", __func__);
152 sshbuf_dump_data(sighash, sizeof(sighash), stderr);
153#endif
154
155 /* Verify it */
156 switch (ECDSA_do_verify(sighash, sizeof(sighash), sig, key->ecdsa)) {
157 case 1:
158 ret = 0;
159 break;
160 case 0:
161 ret = SSH_ERR_SIGNATURE_INVALID;
162 goto out;
163 default:
164 ret = SSH_ERR_LIBCRYPTO_ERROR;
165 goto out;
166 }
167
168 out:
169 explicit_bzero(&sig_flags, sizeof(sig_flags));
170 explicit_bzero(&sig_counter, sizeof(sig_counter));
171 explicit_bzero(msghash, sizeof(msghash));
172 explicit_bzero(sighash, sizeof(msghash));
173 explicit_bzero(apphash, sizeof(apphash));
174 sshbuf_free(original_signed);
175 sshbuf_free(sigbuf);
176 sshbuf_free(b);
177 ECDSA_SIG_free(sig);
178 BN_clear_free(sig_r);
179 BN_clear_free(sig_s);
180 free(ktype);
181 return ret;
182}
Damien Miller764d51e2019-11-01 13:34:49 +1100183#endif /* ENABLE_SK */