Coverage Report

Created: 2025-07-18 06:46

/src/openssh/kexc25519.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: kexc25519.c,v 1.18 2024/09/02 12:13:56 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
2.98k
{
52
2.98k
  static const u_char basepoint[CURVE25519_SIZE] = {9};
53
54
2.98k
  arc4random_buf(key, CURVE25519_SIZE);
55
2.98k
  crypto_scalarmult_curve25519(pub, key, basepoint);
56
2.98k
}
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
862
{
62
862
  u_char shared_key[CURVE25519_SIZE];
63
862
  u_char zero[CURVE25519_SIZE];
64
862
  int r;
65
66
862
  crypto_scalarmult_curve25519(shared_key, key, pub);
67
68
  /* Check for all-zero shared secret */
69
862
  explicit_bzero(zero, CURVE25519_SIZE);
70
862
  if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0)
71
4
    return SSH_ERR_KEY_INVALID_EC_VALUE;
72
73
#ifdef DEBUG_KEXECDH
74
  dump_digest("shared secret 25519", shared_key, CURVE25519_SIZE);
75
#endif
76
858
  if (raw)
77
37
    r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
78
821
  else
79
821
    r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
80
858
  explicit_bzero(shared_key, CURVE25519_SIZE);
81
858
  return r;
82
862
}
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
1.78k
{
94
1.78k
  struct sshbuf *buf = NULL;
95
1.78k
  u_char *cp = NULL;
96
1.78k
  int r;
97
98
1.78k
  if ((buf = sshbuf_new()) == NULL)
99
0
    return SSH_ERR_ALLOC_FAIL;
100
1.78k
  if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
101
0
    goto out;
102
1.78k
  kexc25519_keygen(kex->c25519_client_key, cp);
103
#ifdef DEBUG_KEXECDH
104
  dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
105
#endif
106
1.78k
  kex->client_pub = buf;
107
1.78k
  buf = NULL;
108
1.78k
 out:
109
1.78k
  sshbuf_free(buf);
110
1.78k
  return r;
111
1.78k
}
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
388
{
117
388
  struct sshbuf *server_blob = NULL;
118
388
  struct sshbuf *buf = NULL;
119
388
  const u_char *client_pub;
120
388
  u_char *server_pub;
121
388
  u_char server_key[CURVE25519_SIZE];
122
388
  int r;
123
124
388
  *server_blobp = NULL;
125
388
  *shared_secretp = NULL;
126
127
388
  if (sshbuf_len(client_blob) != CURVE25519_SIZE) {
128
3
    r = SSH_ERR_SIGNATURE_INVALID;
129
3
    goto out;
130
3
  }
131
385
  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
385
  if ((server_blob = sshbuf_new()) == NULL) {
137
0
    r = SSH_ERR_ALLOC_FAIL;
138
0
    goto out;
139
0
  }
140
385
  if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
141
0
    goto out;
142
385
  kexc25519_keygen(server_key, server_pub);
143
  /* allocate shared secret */
144
385
  if ((buf = sshbuf_new()) == NULL) {
145
0
    r = SSH_ERR_ALLOC_FAIL;
146
0
    goto out;
147
0
  }
148
385
  if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0)
149
1
    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
384
  *server_blobp = server_blob;
155
384
  *shared_secretp = buf;
156
384
  server_blob = NULL;
157
384
  buf = NULL;
158
388
 out:
159
388
  explicit_bzero(server_key, sizeof(server_key));
160
388
  sshbuf_free(server_blob);
161
388
  sshbuf_free(buf);
162
388
  return r;
163
384
}
164
165
int
166
kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob,
167
    struct sshbuf **shared_secretp)
168
439
{
169
439
  struct sshbuf *buf = NULL;
170
439
  const u_char *server_pub;
171
439
  int r;
172
173
439
  *shared_secretp = NULL;
174
175
439
  if (sshbuf_len(server_blob) != CURVE25519_SIZE) {
176
1
    r = SSH_ERR_SIGNATURE_INVALID;
177
1
    goto out;
178
1
  }
179
438
  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
438
  if ((buf = sshbuf_new()) == NULL) {
185
0
    r = SSH_ERR_ALLOC_FAIL;
186
0
    goto out;
187
0
  }
188
438
  if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
189
438
      buf, 0)) < 0)
190
1
    goto out;
191
#ifdef DEBUG_KEXECDH
192
  dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
193
#endif
194
437
  *shared_secretp = buf;
195
437
  buf = NULL;
196
439
 out:
197
439
  sshbuf_free(buf);
198
439
  return r;
199
437
}