Coverage Report

Created: 2026-02-14 06:34

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
39
346
static void x25519_free(EvpPkey *pkey) {
40
346
  X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
41
346
  OPENSSL_free(key);
42
346
  pkey->pkey = nullptr;
43
346
}
44
45
351
static int x25519_set_priv_raw(EvpPkey *pkey, const uint8_t *in, size_t len) {
46
351
  if (len != 32) {
47
26
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
48
26
    return 0;
49
26
  }
50
51
325
  X25519_KEY *key = New<X25519_KEY>();
52
325
  if (key == nullptr) {
53
0
    return 0;
54
0
  }
55
56
325
  OPENSSL_memcpy(key->priv, in, 32);
57
325
  X25519_public_from_private(key->pub, key->priv);
58
325
  key->has_private = true;
59
60
325
  evp_pkey_set0(pkey, &x25519_asn1_meth, key);
61
325
  return 1;
62
325
}
63
64
52
static int x25519_set_pub_raw(EvpPkey *pkey, const uint8_t *in, size_t len) {
65
52
  if (len != 32) {
66
31
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
67
31
    return 0;
68
31
  }
69
70
21
  X25519_KEY *key = New<X25519_KEY>();
71
21
  if (key == nullptr) {
72
0
    return 0;
73
0
  }
74
75
21
  OPENSSL_memcpy(key->pub, in, 32);
76
21
  key->has_private = false;
77
78
21
  evp_pkey_set0(pkey, &x25519_asn1_meth, key);
79
21
  return 1;
80
21
}
81
82
static int x25519_get_priv_raw(const EvpPkey *pkey, uint8_t *out,
83
0
                               size_t *out_len) {
84
0
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
85
0
  if (!key->has_private) {
86
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
87
0
    return 0;
88
0
  }
89
90
0
  if (out == nullptr) {
91
0
    *out_len = 32;
92
0
    return 1;
93
0
  }
94
95
0
  if (*out_len < 32) {
96
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
97
0
    return 0;
98
0
  }
99
100
0
  OPENSSL_memcpy(out, key->priv, 32);
101
0
  *out_len = 32;
102
0
  return 1;
103
0
}
104
105
static int x25519_get_pub_raw(const EvpPkey *pkey, uint8_t *out,
106
0
                              size_t *out_len) {
107
0
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
108
0
  if (out == nullptr) {
109
0
    *out_len = 32;
110
0
    return 1;
111
0
  }
112
113
0
  if (*out_len < 32) {
114
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
115
0
    return 0;
116
0
  }
117
118
0
  OPENSSL_memcpy(out, key->pub, 32);
119
0
  *out_len = 32;
120
0
  return 1;
121
0
}
122
123
static int x25519_set1_tls_encodedpoint(EvpPkey *pkey, const uint8_t *in,
124
0
                                        size_t len) {
125
0
  return x25519_set_pub_raw(pkey, in, len);
126
0
}
127
128
static size_t x25519_get1_tls_encodedpoint(const EvpPkey *pkey,
129
0
                                           uint8_t **out_ptr) {
130
0
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
131
0
  if (key == nullptr) {
132
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET);
133
0
    return 0;
134
0
  }
135
136
0
  *out_ptr = reinterpret_cast<uint8_t *>(OPENSSL_memdup(key->pub, 32));
137
0
  return *out_ptr == nullptr ? 0 : 32;
138
0
}
139
140
static bssl::evp_decode_result_t x25519_pub_decode(const EVP_PKEY_ALG *alg,
141
                                                   EvpPkey *out, CBS *params,
142
75
                                                   CBS *key) {
143
  // See RFC 8410, section 4.
144
145
  // The parameters must be omitted. Public keys have length 32.
146
75
  if (CBS_len(params) != 0) {
147
23
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
148
23
    return evp_decode_error;
149
23
  }
150
151
52
  return x25519_set_pub_raw(out, CBS_data(key), CBS_len(key))
152
52
             ? evp_decode_ok
153
52
             : evp_decode_error;
154
75
}
155
156
112
static int x25519_pub_encode(CBB *out, const EvpPkey *pkey) {
157
112
  const X25519_KEY *key = reinterpret_cast<X25519_KEY *>(pkey->pkey);
158
159
  // See RFC 8410, section 4.
160
112
  CBB spki, algorithm, key_bitstring;
161
112
  if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
162
112
      !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
163
112
      !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, x25519_asn1_meth.oid,
164
112
                            x25519_asn1_meth.oid_len) ||
165
112
      !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
166
112
      !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
167
112
      !CBB_add_bytes(&key_bitstring, key->pub, 32) ||  //
168
112
      !CBB_flush(out)) {
169
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
170
0
    return 0;
171
0
  }
172
173
112
  return 1;
174
112
}
175
176
0
static bool x25519_pub_equal(const EvpPkey *a, const EvpPkey *b) {
177
0
  const X25519_KEY *a_key = reinterpret_cast<const X25519_KEY *>(a->pkey);
178
0
  const X25519_KEY *b_key = reinterpret_cast<const X25519_KEY *>(b->pkey);
179
0
  return OPENSSL_memcmp(a_key->pub, b_key->pub, 32) == 0;
180
0
}
181
182
static bssl::evp_decode_result_t x25519_priv_decode(const EVP_PKEY_ALG *alg,
183
                                                    EvpPkey *out, CBS *params,
184
405
                                                    CBS *key) {
185
  // See RFC 8410, section 7.
186
187
  // Parameters must be empty. The key is a 32-byte value wrapped in an extra
188
  // OCTET STRING layer.
189
405
  CBS inner;
190
405
  if (CBS_len(params) != 0 ||
191
389
      !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) || CBS_len(key) != 0) {
192
54
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
193
54
    return evp_decode_error;
194
54
  }
195
196
351
  return x25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner))
197
351
             ? evp_decode_ok
198
351
             : evp_decode_error;
199
405
}
200
201
209
static int x25519_priv_encode(CBB *out, const EvpPkey *pkey) {
202
209
  const X25519_KEY *key = reinterpret_cast<const X25519_KEY *>(pkey->pkey);
203
209
  if (!key->has_private) {
204
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
205
0
    return 0;
206
0
  }
207
208
  // See RFC 8410, section 7.
209
209
  CBB pkcs8, algorithm, private_key, inner;
210
209
  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
211
209
      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
212
209
      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
213
209
      !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, x25519_asn1_meth.oid,
214
209
                            x25519_asn1_meth.oid_len) ||
215
209
      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
216
209
      !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
217
      // The PKCS#8 encoding stores only the 32-byte seed which is the first 32
218
      // bytes of the private key.
219
209
      !CBB_add_bytes(&inner, key->priv, 32) ||  //
220
209
      !CBB_flush(out)) {
221
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
222
0
    return 0;
223
0
  }
224
225
209
  return 1;
226
209
}
227
228
0
static bool x25519_pub_present(const EvpPkey *) { return true; }
229
230
0
static bool x25519_priv_present(const EvpPkey *pk) {
231
0
  const X25519_KEY *key = reinterpret_cast<const X25519_KEY *>(pk->pkey);
232
0
  return key->has_private;
233
0
}
234
235
0
static int x25519_size(const EvpPkey *pkey) { return 32; }
236
237
0
static int x25519_bits(const EvpPkey *pkey) { return 253; }
238
239
const EVP_PKEY_ASN1_METHOD x25519_asn1_meth = {
240
    EVP_PKEY_X25519,
241
    {0x2b, 0x65, 0x6e},
242
    3,
243
    &x25519_pkey_meth,
244
    x25519_pub_decode,
245
    x25519_pub_encode,
246
    x25519_pub_equal,
247
    x25519_pub_present,
248
    x25519_priv_decode,
249
    x25519_priv_encode,
250
    x25519_priv_present,
251
    x25519_set_priv_raw,
252
    /*set_priv_seed=*/nullptr,
253
    x25519_set_pub_raw,
254
    x25519_get_priv_raw,
255
    /*get_priv_seed=*/nullptr,
256
    x25519_get_pub_raw,
257
    x25519_set1_tls_encodedpoint,
258
    x25519_get1_tls_encodedpoint,
259
    /*pkey_opaque=*/nullptr,
260
    x25519_size,
261
    x25519_bits,
262
    /*param_missing=*/nullptr,
263
    /*param_copy=*/nullptr,
264
    /*param_equal=*/nullptr,
265
    x25519_free,
266
};
267
268
}  // namespace
269
270
179k
const EVP_PKEY_ALG *EVP_pkey_x25519() {
271
179k
  static const EVP_PKEY_ALG kAlg = {&x25519_asn1_meth};
272
179k
  return &kAlg;
273
179k
}
274
275
// X25519 has no parameters to copy.
276
0
static int pkey_x25519_copy(EvpPkeyCtx *dst, EvpPkeyCtx *src) { return 1; }
277
278
0
static int pkey_x25519_keygen(EvpPkeyCtx *ctx, EvpPkey *pkey) {
279
0
  X25519_KEY *key = New<X25519_KEY>();
280
0
  if (key == nullptr) {
281
0
    return 0;
282
0
  }
283
284
0
  X25519_keypair(key->pub, key->priv);
285
0
  key->has_private = true;
286
0
  evp_pkey_set0(pkey, &x25519_asn1_meth, key);
287
0
  return 1;
288
0
}
289
290
0
static int pkey_x25519_derive(EvpPkeyCtx *ctx, uint8_t *out, size_t *out_len) {
291
0
  if (ctx->pkey == nullptr || ctx->peerkey == nullptr) {
292
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
293
0
    return 0;
294
0
  }
295
296
0
  const X25519_KEY *our_key =
297
0
      reinterpret_cast<const X25519_KEY *>(ctx->pkey->pkey);
298
0
  const X25519_KEY *peer_key =
299
0
      reinterpret_cast<const X25519_KEY *>(ctx->peerkey->pkey);
300
0
  if (our_key == nullptr || peer_key == nullptr) {
301
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET);
302
0
    return 0;
303
0
  }
304
305
0
  if (!our_key->has_private) {
306
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
307
0
    return 0;
308
0
  }
309
310
0
  if (out != nullptr) {
311
0
    if (*out_len < 32) {
312
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
313
0
      return 0;
314
0
    }
315
0
    if (!X25519(out, our_key->priv, peer_key->pub)) {
316
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PEER_KEY);
317
0
      return 0;
318
0
    }
319
0
  }
320
321
0
  *out_len = 32;
322
0
  return 1;
323
0
}
324
325
0
static int pkey_x25519_ctrl(EvpPkeyCtx *ctx, int type, int p1, void *p2) {
326
0
  switch (type) {
327
0
    case EVP_PKEY_CTRL_PEER_KEY:
328
      // |EVP_PKEY_derive_set_peer| requires the key implement this command,
329
      // even if it is a no-op.
330
0
      return 1;
331
332
0
    default:
333
0
      OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED);
334
0
      return 0;
335
0
  }
336
0
}
337
338
const EVP_PKEY_CTX_METHOD bssl::x25519_pkey_meth = {
339
    /*pkey_id=*/EVP_PKEY_X25519,
340
    /*init=*/nullptr,
341
    /*copy=*/pkey_x25519_copy,
342
    /*cleanup=*/nullptr,
343
    /*keygen=*/pkey_x25519_keygen,
344
    /*sign=*/nullptr,
345
    /*sign_message=*/nullptr,
346
    /*verify=*/nullptr,
347
    /*verify_message=*/nullptr,
348
    /*verify_recover=*/nullptr,
349
    /*encrypt=*/nullptr,
350
    /*decrypt=*/nullptr,
351
    /*derive=*/pkey_x25519_derive,
352
    /*paramgen=*/nullptr,
353
    /*ctrl=*/pkey_x25519_ctrl,
354
};