Coverage Report

Created: 2026-01-10 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/kexc25519.c
Line
Count
Source
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
3.06k
{
52
3.06k
  static const u_char basepoint[CURVE25519_SIZE] = {9};
53
54
3.06k
  arc4random_buf(key, CURVE25519_SIZE);
55
3.06k
  crypto_scalarmult_curve25519(pub, key, basepoint);
56
3.06k
}
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
852
{
62
852
  u_char shared_key[CURVE25519_SIZE];
63
852
  u_char zero[CURVE25519_SIZE];
64
852
  int r;
65
66
852
  crypto_scalarmult_curve25519(shared_key, key, pub);
67
68
  /* Check for all-zero shared secret */
69
852
  explicit_bzero(zero, CURVE25519_SIZE);
70
852
  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
848
  if (raw)
77
19
    r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
78
829
  else
79
829
    r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
80
848
  explicit_bzero(shared_key, CURVE25519_SIZE);
81
848
  return r;
82
852
}
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.85k
{
94
1.85k
  struct sshbuf *buf = NULL;
95
1.85k
  u_char *cp = NULL;
96
1.85k
  int r;
97
98
1.85k
  if ((buf = sshbuf_new()) == NULL)
99
0
    return SSH_ERR_ALLOC_FAIL;
100
1.85k
  if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
101
0
    goto out;
102
1.85k
  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.85k
  kex->client_pub = buf;
107
1.85k
  buf = NULL;
108
1.85k
 out:
109
1.85k
  sshbuf_free(buf);
110
1.85k
  return r;
111
1.85k
}
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
417
{
117
417
  struct sshbuf *server_blob = NULL;
118
417
  struct sshbuf *buf = NULL;
119
417
  const u_char *client_pub;
120
417
  u_char *server_pub;
121
417
  u_char server_key[CURVE25519_SIZE];
122
417
  int r;
123
124
417
  *server_blobp = NULL;
125
417
  *shared_secretp = NULL;
126
127
417
  if (sshbuf_len(client_blob) != CURVE25519_SIZE) {
128
7
    r = SSH_ERR_SIGNATURE_INVALID;
129
7
    goto out;
130
7
  }
131
410
  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
410
  if ((server_blob = sshbuf_new()) == NULL) {
137
0
    r = SSH_ERR_ALLOC_FAIL;
138
0
    goto out;
139
0
  }
140
410
  if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
141
0
    goto out;
142
410
  kexc25519_keygen(server_key, server_pub);
143
  /* allocate shared secret */
144
410
  if ((buf = sshbuf_new()) == NULL) {
145
0
    r = SSH_ERR_ALLOC_FAIL;
146
0
    goto out;
147
0
  }
148
410
  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
409
  *server_blobp = server_blob;
155
409
  *shared_secretp = buf;
156
409
  server_blob = NULL;
157
409
  buf = NULL;
158
417
 out:
159
417
  explicit_bzero(server_key, sizeof(server_key));
160
417
  sshbuf_free(server_blob);
161
417
  sshbuf_free(buf);
162
417
  return r;
163
409
}
164
165
int
166
kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob,
167
    struct sshbuf **shared_secretp)
168
422
{
169
422
  struct sshbuf *buf = NULL;
170
422
  const u_char *server_pub;
171
422
  int r;
172
173
422
  *shared_secretp = NULL;
174
175
422
  if (sshbuf_len(server_blob) != CURVE25519_SIZE) {
176
1
    r = SSH_ERR_SIGNATURE_INVALID;
177
1
    goto out;
178
1
  }
179
421
  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
421
  if ((buf = sshbuf_new()) == NULL) {
185
0
    r = SSH_ERR_ALLOC_FAIL;
186
0
    goto out;
187
0
  }
188
421
  if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
189
421
      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
420
  *shared_secretp = buf;
195
420
  buf = NULL;
196
422
 out:
197
422
  sshbuf_free(buf);
198
422
  return r;
199
420
}