Coverage Report

Created: 2026-04-30 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/evp/p_x25519.cc
Line
Count
Source
1
// Copyright 2019 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/evp.h>
16
17
#include <openssl/bytestring.h>
18
#include <openssl/curve25519.h>
19
#include <openssl/err.h>
20
#include <openssl/mem.h>
21
22
#include "../internal.h"
23
#include "../mem_internal.h"
24
#include "internal.h"
25
26
27
using namespace bssl;
28
29
namespace {
30
31
struct X25519_KEY {
32
  uint8_t pub[32];
33
  uint8_t priv[32];
34
  bool has_private;
35
};
36
37
extern const EVP_PKEY_ASN1_METHOD x25519_asn1_meth;
38
extern const EVP_PKEY_CTX_METHOD x25519_pkey_meth;
39
40
504
static void x25519_free(EvpPkey *pkey) {
41
504
  X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
42
504
  OPENSSL_free(key);
43
504
  pkey->pkey = nullptr;
44
504
}
45
46
508
static int x25519_set_priv_raw(EvpPkey *pkey, const uint8_t *in, size_t len) {
47
508
  if (len != 32) {
48
40
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
49
40
    return 0;
50
40
  }
51
52
468
  X25519_KEY *key = New<X25519_KEY>();
53
468
  if (key == nullptr) {
54
0
    return 0;
55
0
  }
56
57
468
  OPENSSL_memcpy(key->priv, in, 32);
58
468
  X25519_public_from_private(key->pub, key->priv);
59
468
  key->has_private = true;
60
61
468
  evp_pkey_set0(pkey, &x25519_asn1_meth, key);
62
468
  return 1;
63
468
}
64
65
65
static int x25519_set_pub_raw(EvpPkey *pkey, const uint8_t *in, size_t len) {
66
65
  if (len != 32) {
67
29
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
68
29
    return 0;
69
29
  }
70
71
36
  X25519_KEY *key = New<X25519_KEY>();
72
36
  if (key == nullptr) {
73
0
    return 0;
74
0
  }
75
76
36
  OPENSSL_memcpy(key->pub, in, 32);
77
36
  key->has_private = false;
78
79
36
  evp_pkey_set0(pkey, &x25519_asn1_meth, key);
80
36
  return 1;
81
36
}
82
83
static int x25519_get_priv_raw(const EvpPkey *pkey, uint8_t *out,
84
0
                               size_t *out_len) {
85
0
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
86
0
  if (!key->has_private) {
87
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
88
0
    return 0;
89
0
  }
90
91
0
  if (out == nullptr) {
92
0
    *out_len = 32;
93
0
    return 1;
94
0
  }
95
96
0
  if (*out_len < 32) {
97
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
98
0
    return 0;
99
0
  }
100
101
0
  OPENSSL_memcpy(out, key->priv, 32);
102
0
  *out_len = 32;
103
0
  return 1;
104
0
}
105
106
static int x25519_get_pub_raw(const EvpPkey *pkey, uint8_t *out,
107
0
                              size_t *out_len) {
108
0
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
109
0
  if (out == nullptr) {
110
0
    *out_len = 32;
111
0
    return 1;
112
0
  }
113
114
0
  if (*out_len < 32) {
115
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
116
0
    return 0;
117
0
  }
118
119
0
  OPENSSL_memcpy(out, key->pub, 32);
120
0
  *out_len = 32;
121
0
  return 1;
122
0
}
123
124
static int x25519_set1_tls_encodedpoint(EvpPkey *pkey, const uint8_t *in,
125
0
                                        size_t len) {
126
0
  return x25519_set_pub_raw(pkey, in, len);
127
0
}
128
129
static size_t x25519_get1_tls_encodedpoint(const EvpPkey *pkey,
130
0
                                           uint8_t **out_ptr) {
131
0
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
132
0
  if (key == nullptr) {
133
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
134
0
    return 0;
135
0
  }
136
137
0
  *out_ptr = reinterpret_cast<uint8_t *>(OPENSSL_memdup(key->pub, 32));
138
0
  return *out_ptr == nullptr ? 0 : 32;
139
0
}
140
141
static bssl::evp_decode_result_t x25519_pub_decode(const EVP_PKEY_ALG *alg,
142
                                                   EvpPkey *out, CBS *params,
143
86
                                                   CBS *key) {
144
  // See RFC 8410, section 4.
145
146
  // The parameters must be omitted. Public keys have length 32.
147
86
  if (CBS_len(params) != 0) {
148
21
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
149
21
    return evp_decode_error;
150
21
  }
151
152
65
  return x25519_set_pub_raw(out, CBS_data(key), CBS_len(key))
153
65
             ? evp_decode_ok
154
65
             : evp_decode_error;
155
86
}
156
157
167
static int x25519_pub_encode(CBB *out, const EvpPkey *pkey) {
158
167
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
159
160
  // See RFC 8410, section 4.
161
167
  CBB spki, algorithm, key_bitstring;
162
167
  if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
163
167
      !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
164
167
      !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, x25519_asn1_meth.oid,
165
167
                            x25519_asn1_meth.oid_len) ||
166
167
      !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
167
167
      !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
168
167
      !CBB_add_bytes(&key_bitstring, key->pub, 32) ||  //
169
167
      !CBB_flush(out)) {
170
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
171
0
    return 0;
172
0
  }
173
174
167
  return 1;
175
167
}
176
177
0
static bool x25519_pub_equal(const EvpPkey *a, const EvpPkey *b) {
178
0
  const X25519_KEY *a_key = reinterpret_cast<const X25519_KEY *>(a->pkey);
179
0
  const X25519_KEY *b_key = reinterpret_cast<const X25519_KEY *>(b->pkey);
180
0
  return OPENSSL_memcmp(a_key->pub, b_key->pub, 32) == 0;
181
0
}
182
183
static bssl::evp_decode_result_t x25519_priv_decode(const EVP_PKEY_ALG *alg,
184
                                                    EvpPkey *out, CBS *params,
185
561
                                                    CBS *key) {
186
  // See RFC 8410, section 7.
187
188
  // Parameters must be empty. The key is a 32-byte value wrapped in an extra
189
  // OCTET STRING layer.
190
561
  CBS inner;
191
561
  if (CBS_len(params) != 0 ||
192
534
      !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) || CBS_len(key) != 0) {
193
53
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
194
53
    return evp_decode_error;
195
53
  }
196
197
508
  return x25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner))
198
508
             ? evp_decode_ok
199
508
             : evp_decode_error;
200
561
}
201
202
317
static int x25519_priv_encode(CBB *out, const EvpPkey *pkey) {
203
317
  const X25519_KEY *key = reinterpret_cast<const X25519_KEY *>(pkey->pkey);
204
317
  if (!key->has_private) {
205
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
206
0
    return 0;
207
0
  }
208
209
  // See RFC 8410, section 7.
210
317
  CBB pkcs8, algorithm, private_key, inner;
211
317
  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
212
317
      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
213
317
      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
214
317
      !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, x25519_asn1_meth.oid,
215
317
                            x25519_asn1_meth.oid_len) ||
216
317
      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
217
317
      !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
218
      // The PKCS#8 encoding stores only the 32-byte seed which is the first 32
219
      // bytes of the private key.
220
317
      !CBB_add_bytes(&inner, key->priv, 32) ||  //
221
317
      !CBB_flush(out)) {
222
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
223
0
    return 0;
224
0
  }
225
226
317
  return 1;
227
317
}
228
229
0
static bool x25519_pub_present(const EvpPkey *) { return true; }
230
231
0
static bool x25519_pub_copy(EvpPkey *out, const EvpPkey *pkey) {
232
0
  const X25519_KEY *pkey_x25519 =
233
0
      reinterpret_cast<const X25519_KEY *>(pkey->pkey);
234
0
  X25519_KEY *public_copy = New<X25519_KEY>();
235
0
  if (public_copy == nullptr) {
236
0
    return false;
237
0
  }
238
0
  OPENSSL_memcpy(public_copy->pub, pkey_x25519->pub, 32);
239
0
  public_copy->has_private = false;
240
0
  evp_pkey_set0(out, pkey->ameth, public_copy);
241
0
  return true;
242
0
}
243
244
0
static bool x25519_priv_present(const EvpPkey *pk) {
245
0
  const X25519_KEY *key = reinterpret_cast<const X25519_KEY *>(pk->pkey);
246
0
  return key->has_private;
247
0
}
248
249
0
static int x25519_size(const EvpPkey *pkey) { return 32; }
250
251
0
static int x25519_bits(const EvpPkey *pkey) { return 253; }
252
253
const EVP_PKEY_ASN1_METHOD x25519_asn1_meth = {
254
    EVP_PKEY_X25519,
255
    {0x2b, 0x65, 0x6e},
256
    3,
257
    &x25519_pkey_meth,
258
    x25519_pub_decode,
259
    x25519_pub_encode,
260
    x25519_pub_equal,
261
    x25519_pub_present,
262
    x25519_pub_copy,
263
    x25519_priv_decode,
264
    x25519_priv_encode,
265
    x25519_priv_present,
266
    x25519_set_priv_raw,
267
    /*set_priv_seed=*/nullptr,
268
    x25519_set_pub_raw,
269
    x25519_get_priv_raw,
270
    /*get_priv_seed=*/nullptr,
271
    x25519_get_pub_raw,
272
    x25519_set1_tls_encodedpoint,
273
    x25519_get1_tls_encodedpoint,
274
    /*pkey_opaque=*/nullptr,
275
    x25519_size,
276
    x25519_bits,
277
    /*param_missing=*/nullptr,
278
    /*param_copy=*/nullptr,
279
    /*param_equal=*/nullptr,
280
    x25519_free,
281
};
282
283
// X25519 has no parameters to copy.
284
0
static int pkey_x25519_copy(EvpPkeyCtx *dst, EvpPkeyCtx *src) { return 1; }
285
286
0
static int pkey_x25519_keygen(EvpPkeyCtx *ctx, EvpPkey *pkey) {
287
0
  X25519_KEY *key = New<X25519_KEY>();
288
0
  if (key == nullptr) {
289
0
    return 0;
290
0
  }
291
292
0
  X25519_keypair(key->pub, key->priv);
293
0
  key->has_private = true;
294
0
  evp_pkey_set0(pkey, &x25519_asn1_meth, key);
295
0
  return 1;
296
0
}
297
298
0
static int pkey_x25519_derive(EvpPkeyCtx *ctx, uint8_t *out, size_t *out_len) {
299
0
  if (ctx->pkey == nullptr || ctx->peerkey == nullptr) {
300
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
301
0
    return 0;
302
0
  }
303
304
0
  const X25519_KEY *our_key =
305
0
      reinterpret_cast<const X25519_KEY *>(ctx->pkey->pkey);
306
0
  const X25519_KEY *peer_key =
307
0
      reinterpret_cast<const X25519_KEY *>(ctx->peerkey->pkey);
308
0
  if (our_key == nullptr || peer_key == nullptr) {
309
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
310
0
    return 0;
311
0
  }
312
313
0
  if (!our_key->has_private) {
314
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
315
0
    return 0;
316
0
  }
317
318
0
  if (out != nullptr) {
319
0
    if (*out_len < 32) {
320
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
321
0
      return 0;
322
0
    }
323
0
    if (!X25519(out, our_key->priv, peer_key->pub)) {
324
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
325
0
      return 0;
326
0
    }
327
0
  }
328
329
0
  *out_len = 32;
330
0
  return 1;
331
0
}
332
333
0
static int pkey_x25519_ctrl(EvpPkeyCtx *ctx, int type, int p1, void *p2) {
334
0
  switch (type) {
335
0
    case EVP_PKEY_CTRL_PEER_KEY:
336
      // |EVP_PKEY_derive_set_peer| requires the key implement this command,
337
      // even if it is a no-op.
338
0
      return 1;
339
340
0
    default:
341
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
342
0
      return 0;
343
0
  }
344
0
}
345
346
const EVP_PKEY_CTX_METHOD x25519_pkey_meth = {
347
    /*pkey_id=*/EVP_PKEY_X25519,
348
    /*init=*/nullptr,
349
    /*copy=*/pkey_x25519_copy,
350
    /*cleanup=*/nullptr,
351
    /*keygen=*/pkey_x25519_keygen,
352
    /*sign=*/nullptr,
353
    /*sign_message=*/nullptr,
354
    /*verify=*/nullptr,
355
    /*verify_message=*/nullptr,
356
    /*verify_recover=*/nullptr,
357
    /*encrypt=*/nullptr,
358
    /*decrypt=*/nullptr,
359
    /*derive=*/pkey_x25519_derive,
360
    /*paramgen=*/nullptr,
361
    /*encap=*/nullptr,
362
    /*decap=*/nullptr,
363
    /*ctrl=*/pkey_x25519_ctrl,
364
};
365
366
}  // namespace
367
368
203k
const EVP_PKEY_ALG *EVP_pkey_x25519() {
369
203k
  static const EVP_PKEY_ALG kAlg = {&x25519_asn1_meth, &x25519_pkey_meth};
370
203k
  return &kAlg;
371
203k
}