Coverage Report

Created: 2024-06-18 06:23

/src/hpn-ssh/kexc25519.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: kexc25519.c,v 1.17 2019/01/21 10:40:11 djm Exp $ */
2
/*
3
 * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4
 * Copyright (c) 2010 Damien Miller.  All rights reserved.
5
 * Copyright (c) 2013 Aris Adamantiadis.  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
#include "includes.h"
29
30
#include <sys/types.h>
31
32
#include <stdio.h>
33
#include <string.h>
34
#include <signal.h>
35
36
#include "sshkey.h"
37
#include "kex.h"
38
#include "sshbuf.h"
39
#include "digest.h"
40
#include "ssherr.h"
41
#include "ssh2.h"
42
43
extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
44
    const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
45
  __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
46
  __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
47
  __attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
48
49
void
50
kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
51
0
{
52
0
  static const u_char basepoint[CURVE25519_SIZE] = {9};
53
54
0
  arc4random_buf(key, CURVE25519_SIZE);
55
0
  crypto_scalarmult_curve25519(pub, key, basepoint);
56
0
}
57
58
int
59
kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
60
    const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw)
61
0
{
62
0
  u_char shared_key[CURVE25519_SIZE];
63
0
  u_char zero[CURVE25519_SIZE];
64
0
  int r;
65
66
0
  crypto_scalarmult_curve25519(shared_key, key, pub);
67
68
  /* Check for all-zero shared secret */
69
0
  explicit_bzero(zero, CURVE25519_SIZE);
70
0
  if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0)
71
0
    return SSH_ERR_KEY_INVALID_EC_VALUE;
72
73
#ifdef DEBUG_KEXECDH
74
  dump_digest("shared secret", shared_key, CURVE25519_SIZE);
75
#endif
76
0
  if (raw)
77
0
    r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
78
0
  else
79
0
    r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
80
0
  explicit_bzero(shared_key, CURVE25519_SIZE);
81
0
  return r;
82
0
}
83
84
int
85
kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
86
    const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
87
0
{
88
0
  return kexc25519_shared_key_ext(key, pub, out, 0);
89
0
}
90
91
int
92
kex_c25519_keypair(struct kex *kex)
93
0
{
94
0
  struct sshbuf *buf = NULL;
95
0
  u_char *cp = NULL;
96
0
  int r;
97
98
0
  if ((buf = sshbuf_new()) == NULL)
99
0
    return SSH_ERR_ALLOC_FAIL;
100
0
  if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
101
0
    goto out;
102
0
  kexc25519_keygen(kex->c25519_client_key, cp);
103
#ifdef DEBUG_KEXECDH
104
  dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
105
#endif
106
0
  kex->client_pub = buf;
107
0
  buf = NULL;
108
0
 out:
109
0
  sshbuf_free(buf);
110
0
  return r;
111
0
}
112
113
int
114
kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
115
   struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
116
0
{
117
0
  struct sshbuf *server_blob = NULL;
118
0
  struct sshbuf *buf = NULL;
119
0
  const u_char *client_pub;
120
0
  u_char *server_pub;
121
0
  u_char server_key[CURVE25519_SIZE];
122
0
  int r;
123
124
0
  *server_blobp = NULL;
125
0
  *shared_secretp = NULL;
126
127
0
  if (sshbuf_len(client_blob) != CURVE25519_SIZE) {
128
0
    r = SSH_ERR_SIGNATURE_INVALID;
129
0
    goto out;
130
0
  }
131
0
  client_pub = sshbuf_ptr(client_blob);
132
#ifdef DEBUG_KEXECDH
133
  dump_digest("client public key 25519:", client_pub, CURVE25519_SIZE);
134
#endif
135
  /* allocate space for encrypted KEM key and ECDH pub key */
136
0
  if ((server_blob = sshbuf_new()) == NULL) {
137
0
    r = SSH_ERR_ALLOC_FAIL;
138
0
    goto out;
139
0
  }
140
0
  if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
141
0
    goto out;
142
0
  kexc25519_keygen(server_key, server_pub);
143
  /* allocate shared secret */
144
0
  if ((buf = sshbuf_new()) == NULL) {
145
0
    r = SSH_ERR_ALLOC_FAIL;
146
0
    goto out;
147
0
  }
148
0
  if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0)
149
0
    goto out;
150
#ifdef DEBUG_KEXECDH
151
  dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
152
  dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
153
#endif
154
0
  *server_blobp = server_blob;
155
0
  *shared_secretp = buf;
156
0
  server_blob = NULL;
157
0
  buf = NULL;
158
0
 out:
159
0
  explicit_bzero(server_key, sizeof(server_key));
160
0
  sshbuf_free(server_blob);
161
0
  sshbuf_free(buf);
162
0
  return r;
163
0
}
164
165
int
166
kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob,
167
    struct sshbuf **shared_secretp)
168
0
{
169
0
  struct sshbuf *buf = NULL;
170
0
  const u_char *server_pub;
171
0
  int r;
172
173
0
  *shared_secretp = NULL;
174
175
0
  if (sshbuf_len(server_blob) != CURVE25519_SIZE) {
176
0
    r = SSH_ERR_SIGNATURE_INVALID;
177
0
    goto out;
178
0
  }
179
0
  server_pub = sshbuf_ptr(server_blob);
180
#ifdef DEBUG_KEXECDH
181
  dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
182
#endif
183
  /* shared secret */
184
0
  if ((buf = sshbuf_new()) == NULL) {
185
0
    r = SSH_ERR_ALLOC_FAIL;
186
0
    goto out;
187
0
  }
188
0
  if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
189
0
      buf, 0)) < 0)
190
0
    goto out;
191
#ifdef DEBUG_KEXECDH
192
  dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
193
#endif
194
0
  *shared_secretp = buf;
195
0
  buf = NULL;
196
0
 out:
197
0
  sshbuf_free(buf);
198
0
  return r;
199
0
}