summaryrefslogtreecommitdiff
path: root/ssh-ecdsa-sk.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-10-31 21:15:14 +0000
committerDamien Miller <djm@mindrot.org>2019-11-01 09:46:08 +1100
commit02bb0768a937e50bbb236efc2bbdddb1991b1c85 (patch)
treed0a182540b8034345b20a49a09cbf90b234cad1c /ssh-ecdsa-sk.c
parent57ecc10628b04c384cbba2fbc87d38b74cd1199d (diff)
upstream: Initial infrastructure for U2F/FIDO support
Key library support: including allocation, marshalling public/private keys and certificates, signature validation. feedback & ok markus@ OpenBSD-Commit-ID: a17615ba15e0f7932ac4360cb18fc9a9544e68c7
Diffstat (limited to 'ssh-ecdsa-sk.c')
-rw-r--r--ssh-ecdsa-sk.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c
new file mode 100644
index 000000000..6441cd7fa
--- /dev/null
+++ b/ssh-ecdsa-sk.c
@@ -0,0 +1,180 @@
1/* $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
32#include <sys/types.h>
33
34#include <openssl/bn.h>
35#include <openssl/ec.h>
36#include <openssl/ecdsa.h>
37#include <openssl/evp.h>
38
39#include <string.h>
40#include <stdio.h> /* needed for DEBUG_SK only */
41
42#include "sshbuf.h"
43#include "ssherr.h"
44#include "digest.h"
45#define SSHKEY_INTERNAL
46#include "sshkey.h"
47
48/* ARGSUSED */
49int
50ssh_ecdsa_sk_verify(const struct sshkey *key,
51 const u_char *signature, size_t signaturelen,
52 const u_char *data, size_t datalen, u_int compat)
53{
54 ECDSA_SIG *sig = NULL;
55 BIGNUM *sig_r = NULL, *sig_s = NULL;
56 u_char sig_flags;
57 u_char msghash[32], apphash[32], sighash[32];
58 u_int sig_counter;
59 int ret = SSH_ERR_INTERNAL_ERROR;
60 struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL;
61 char *ktype = NULL;
62#ifdef DEBUG_SK
63 char *tmp = NULL;
64#endif
65
66 if (key == NULL || key->ecdsa == NULL ||
67 sshkey_type_plain(key->type) != KEY_ECDSA_SK ||
68 signature == NULL || signaturelen == 0)
69 return SSH_ERR_INVALID_ARGUMENT;
70
71 if (key->ecdsa_nid != NID_X9_62_prime256v1)
72 return SSH_ERR_INTERNAL_ERROR;
73
74 /* fetch signature */
75 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
76 return SSH_ERR_ALLOC_FAIL;
77 if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
78 sshbuf_froms(b, &sigbuf) != 0) {
79 ret = SSH_ERR_INVALID_FORMAT;
80 goto out;
81 }
82 if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
83 ret = SSH_ERR_KEY_TYPE_MISMATCH;
84 goto out;
85 }
86 if (sshbuf_len(b) != 0) {
87 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
88 goto out;
89 }
90
91 /* parse signature */
92 if (sshbuf_get_bignum2(sigbuf, &sig_r) != 0 ||
93 sshbuf_get_bignum2(sigbuf, &sig_s) != 0 ||
94 sshbuf_get_u8(sigbuf, &sig_flags) != 0 ||
95 sshbuf_get_u32(sigbuf, &sig_counter) != 0) {
96 ret = SSH_ERR_INVALID_FORMAT;
97 goto out;
98 }
99 if ((sig = ECDSA_SIG_new()) == NULL) {
100 ret = SSH_ERR_ALLOC_FAIL;
101 goto out;
102 }
103 if (!ECDSA_SIG_set0(sig, sig_r, sig_s)) {
104 ret = SSH_ERR_LIBCRYPTO_ERROR;
105 goto out;
106 }
107#ifdef DEBUG_SK
108 fprintf(stderr, "%s: sig_r: %s\n", __func__, (tmp = BN_bn2hex(sig_r)));
109 free(tmp);
110 fprintf(stderr, "%s: sig_s: %s\n", __func__, (tmp = BN_bn2hex(sig_s)));
111 free(tmp);
112 fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
113 __func__, sig_flags, sig_counter);
114#endif
115 sig_r = sig_s = NULL; /* transferred */
116
117 if (sshbuf_len(sigbuf) != 0) {
118 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
119 goto out;
120 }
121
122 /* Reconstruct data that was supposedly signed */
123 if ((original_signed = sshbuf_new()) == NULL)
124 return SSH_ERR_ALLOC_FAIL;
125 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,
126 msghash, sizeof(msghash))) != 0)
127 goto out;
128 /* Application value is hashed before signature */
129 if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application,
130 strlen(key->sk_application), apphash, sizeof(apphash))) != 0)
131 goto out;
132#ifdef DEBUG_SK
133 fprintf(stderr, "%s: hashed message:\n", __func__);
134 sshbuf_dump_data(msghash, sizeof(msghash), stderr);
135#endif
136 if ((ret = sshbuf_put(original_signed,
137 apphash, sizeof(apphash))) != 0 ||
138 (ret = sshbuf_put_u8(original_signed, sig_flags)) != 0 ||
139 (ret = sshbuf_put_u32(original_signed, sig_counter)) != 0 ||
140 (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0)
141 goto out;
142 /* Signature is over H(original_signed) */
143 if ((ret = ssh_digest_buffer(SSH_DIGEST_SHA256, original_signed,
144 sighash, sizeof(sighash))) != 0)
145 goto out;
146#ifdef DEBUG_SK
147 fprintf(stderr, "%s: signed buf:\n", __func__);
148 sshbuf_dump(original_signed, stderr);
149 fprintf(stderr, "%s: signed hash:\n", __func__);
150 sshbuf_dump_data(sighash, sizeof(sighash), stderr);
151#endif
152
153 /* Verify it */
154 switch (ECDSA_do_verify(sighash, sizeof(sighash), sig, key->ecdsa)) {
155 case 1:
156 ret = 0;
157 break;
158 case 0:
159 ret = SSH_ERR_SIGNATURE_INVALID;
160 goto out;
161 default:
162 ret = SSH_ERR_LIBCRYPTO_ERROR;
163 goto out;
164 }
165
166 out:
167 explicit_bzero(&sig_flags, sizeof(sig_flags));
168 explicit_bzero(&sig_counter, sizeof(sig_counter));
169 explicit_bzero(msghash, sizeof(msghash));
170 explicit_bzero(sighash, sizeof(msghash));
171 explicit_bzero(apphash, sizeof(apphash));
172 sshbuf_free(original_signed);
173 sshbuf_free(sigbuf);
174 sshbuf_free(b);
175 ECDSA_SIG_free(sig);
176 BN_clear_free(sig_r);
177 BN_clear_free(sig_s);
178 free(ktype);
179 return ret;
180}