Coverage Report

Created: 2025-11-03 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/evp/p_ed25519.cc
Line
Count
Source
1
// Copyright 2017 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 "internal.h"
24
25
namespace {
26
27
struct ED25519_KEY {
28
  // key is the concatenation of the private seed and public key. It is stored
29
  // as a single 64-bit array to allow passing to |ED25519_sign|. If
30
  // |has_private| is false, the first 32 bytes are uninitialized and the public
31
  // key is in the last 32 bytes.
32
  uint8_t key[64];
33
  bool has_private;
34
};
35
36
extern const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth;
37
38
266
#define ED25519_PUBLIC_KEY_OFFSET 32
39
40
286
static void ed25519_free(EVP_PKEY *pkey) {
41
286
  OPENSSL_free(pkey->pkey);
42
286
  pkey->pkey = nullptr;
43
286
}
44
45
80
static int ed25519_set_priv_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
46
80
  if (len != 32) {
47
51
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
48
51
    return 0;
49
51
  }
50
51
29
  ED25519_KEY *key =
52
29
      reinterpret_cast<ED25519_KEY *>(OPENSSL_malloc(sizeof(ED25519_KEY)));
53
29
  if (key == nullptr) {
54
0
    return 0;
55
0
  }
56
57
  // The RFC 8032 encoding stores only the 32-byte seed, so we must recover the
58
  // full representation which we use from it.
59
29
  uint8_t pubkey_unused[32];
60
29
  ED25519_keypair_from_seed(pubkey_unused, key->key, in);
61
29
  key->has_private = true;
62
29
  evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
63
29
  return 1;
64
29
}
65
66
314
static int ed25519_set_pub_raw(EVP_PKEY *pkey, const uint8_t *in, size_t len) {
67
314
  if (len != 32) {
68
57
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
69
57
    return 0;
70
57
  }
71
72
257
  ED25519_KEY *key =
73
257
      reinterpret_cast<ED25519_KEY *>(OPENSSL_malloc(sizeof(ED25519_KEY)));
74
257
  if (key == nullptr) {
75
0
    return 0;
76
0
  }
77
78
257
  OPENSSL_memcpy(key->key + ED25519_PUBLIC_KEY_OFFSET, in, 32);
79
257
  key->has_private = false;
80
257
  evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
81
257
  return 1;
82
257
}
83
84
static int ed25519_get_priv_raw(const EVP_PKEY *pkey, uint8_t *out,
85
0
                                size_t *out_len) {
86
0
  const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey);
87
0
  if (!key->has_private) {
88
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
89
0
    return 0;
90
0
  }
91
92
0
  if (out == nullptr) {
93
0
    *out_len = 32;
94
0
    return 1;
95
0
  }
96
97
0
  if (*out_len < 32) {
98
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
99
0
    return 0;
100
0
  }
101
102
  // The raw private key format is the first 32 bytes of the private key.
103
0
  OPENSSL_memcpy(out, key->key, 32);
104
0
  *out_len = 32;
105
0
  return 1;
106
0
}
107
108
static int ed25519_get_pub_raw(const EVP_PKEY *pkey, uint8_t *out,
109
0
                               size_t *out_len) {
110
0
  const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey);
111
0
  if (out == nullptr) {
112
0
    *out_len = 32;
113
0
    return 1;
114
0
  }
115
116
0
  if (*out_len < 32) {
117
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
118
0
    return 0;
119
0
  }
120
121
0
  OPENSSL_memcpy(out, key->key + ED25519_PUBLIC_KEY_OFFSET, 32);
122
0
  *out_len = 32;
123
0
  return 1;
124
0
}
125
126
static evp_decode_result_t ed25519_pub_decode(const EVP_PKEY_ALG *alg,
127
                                              EVP_PKEY *out, CBS *params,
128
356
                                              CBS *key) {
129
  // See RFC 8410, section 4.
130
131
  // The parameters must be omitted. Public keys have length 32.
132
356
  if (CBS_len(params) != 0) {
133
42
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
134
42
    return evp_decode_error;
135
42
  }
136
137
314
  return ed25519_set_pub_raw(out, CBS_data(key), CBS_len(key))
138
314
             ? evp_decode_ok
139
314
             : evp_decode_error;
140
356
}
141
142
9
static int ed25519_pub_encode(CBB *out, const EVP_PKEY *pkey) {
143
9
  const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey);
144
145
  // See RFC 8410, section 4.
146
9
  CBB spki, algorithm, key_bitstring;
147
9
  if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
148
9
      !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
149
9
      !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, ed25519_asn1_meth.oid,
150
9
                            ed25519_asn1_meth.oid_len) ||
151
9
      !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
152
9
      !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
153
9
      !CBB_add_bytes(&key_bitstring, key->key + ED25519_PUBLIC_KEY_OFFSET,
154
9
                     32) ||
155
9
      !CBB_flush(out)) {
156
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
157
0
    return 0;
158
0
  }
159
160
9
  return 1;
161
9
}
162
163
0
static int ed25519_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) {
164
0
  const ED25519_KEY *a_key = reinterpret_cast<const ED25519_KEY *>(a->pkey);
165
0
  const ED25519_KEY *b_key = reinterpret_cast<const ED25519_KEY *>(b->pkey);
166
0
  return OPENSSL_memcmp(a_key->key + ED25519_PUBLIC_KEY_OFFSET,
167
0
                        b_key->key + ED25519_PUBLIC_KEY_OFFSET, 32) == 0;
168
0
}
169
170
static evp_decode_result_t ed25519_priv_decode(const EVP_PKEY_ALG *alg,
171
                                               EVP_PKEY *out, CBS *params,
172
123
                                               CBS *key) {
173
  // See RFC 8410, section 7.
174
175
  // Parameters must be empty. The key is a 32-byte value wrapped in an extra
176
  // OCTET STRING layer.
177
123
  CBS inner;
178
123
  if (CBS_len(params) != 0 ||
179
114
      !CBS_get_asn1(key, &inner, CBS_ASN1_OCTETSTRING) || CBS_len(key) != 0) {
180
43
    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
181
43
    return evp_decode_error;
182
43
  }
183
184
80
  return ed25519_set_priv_raw(out, CBS_data(&inner), CBS_len(&inner))
185
80
             ? evp_decode_ok
186
80
             : evp_decode_error;
187
123
}
188
189
23
static int ed25519_priv_encode(CBB *out, const EVP_PKEY *pkey) {
190
23
  const ED25519_KEY *key = reinterpret_cast<const ED25519_KEY *>(pkey->pkey);
191
23
  if (!key->has_private) {
192
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
193
0
    return 0;
194
0
  }
195
196
  // See RFC 8410, section 7.
197
23
  CBB pkcs8, algorithm, private_key, inner;
198
23
  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
199
23
      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
200
23
      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
201
23
      !CBB_add_asn1_element(&algorithm, CBS_ASN1_OBJECT, ed25519_asn1_meth.oid,
202
23
                            ed25519_asn1_meth.oid_len) ||
203
23
      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
204
23
      !CBB_add_asn1(&private_key, &inner, CBS_ASN1_OCTETSTRING) ||
205
      // The PKCS#8 encoding stores only the 32-byte seed which is the first 32
206
      // bytes of the private key.
207
23
      !CBB_add_bytes(&inner, key->key, 32) ||  //
208
23
      !CBB_flush(out)) {
209
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
210
0
    return 0;
211
0
  }
212
213
23
  return 1;
214
23
}
215
216
0
static int ed25519_size(const EVP_PKEY *pkey) { return 64; }
217
218
0
static int ed25519_bits(const EVP_PKEY *pkey) { return 253; }
219
220
const EVP_PKEY_ASN1_METHOD ed25519_asn1_meth = {
221
    EVP_PKEY_ED25519,
222
    {0x2b, 0x65, 0x70},
223
    3,
224
    &ed25519_pkey_meth,
225
    ed25519_pub_decode,
226
    ed25519_pub_encode,
227
    ed25519_pub_cmp,
228
    ed25519_priv_decode,
229
    ed25519_priv_encode,
230
    ed25519_set_priv_raw,
231
    /*set_priv_seed=*/nullptr,
232
    ed25519_set_pub_raw,
233
    ed25519_get_priv_raw,
234
    /*get_priv_seed=*/nullptr,
235
    ed25519_get_pub_raw,
236
    /*set1_tls_encodedpoint=*/nullptr,
237
    /*get1_tls_encodedpoint=*/nullptr,
238
    /*pkey_opaque=*/nullptr,
239
    ed25519_size,
240
    ed25519_bits,
241
    /*param_missing=*/nullptr,
242
    /*param_copy=*/nullptr,
243
    /*param_cmp=*/nullptr,
244
    ed25519_free,
245
};
246
247
// Ed25519 has no parameters to copy.
248
0
static int pkey_ed25519_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { return 1; }
249
250
0
static int pkey_ed25519_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) {
251
0
  ED25519_KEY *key =
252
0
      reinterpret_cast<ED25519_KEY *>(OPENSSL_malloc(sizeof(ED25519_KEY)));
253
0
  if (key == nullptr) {
254
0
    return 0;
255
0
  }
256
257
0
  uint8_t pubkey_unused[32];
258
0
  ED25519_keypair(pubkey_unused, key->key);
259
0
  key->has_private = true;
260
261
0
  evp_pkey_set0(pkey, &ed25519_asn1_meth, key);
262
0
  return 1;
263
0
}
264
265
static int pkey_ed25519_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig,
266
                                     size_t *siglen, const uint8_t *tbs,
267
0
                                     size_t tbslen) {
268
0
  const ED25519_KEY *key =
269
0
      reinterpret_cast<const ED25519_KEY *>(ctx->pkey->pkey);
270
0
  if (!key->has_private) {
271
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_NOT_A_PRIVATE_KEY);
272
0
    return 0;
273
0
  }
274
275
0
  if (sig == nullptr) {
276
0
    *siglen = 64;
277
0
    return 1;
278
0
  }
279
280
0
  if (*siglen < 64) {
281
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL);
282
0
    return 0;
283
0
  }
284
285
0
  if (!ED25519_sign(sig, tbs, tbslen, key->key)) {
286
0
    return 0;
287
0
  }
288
289
0
  *siglen = 64;
290
0
  return 1;
291
0
}
292
293
static int pkey_ed25519_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig,
294
                                       size_t siglen, const uint8_t *tbs,
295
0
                                       size_t tbslen) {
296
0
  const ED25519_KEY *key =
297
0
      reinterpret_cast<const ED25519_KEY *>(ctx->pkey->pkey);
298
0
  if (siglen != 64 ||
299
0
      !ED25519_verify(tbs, tbslen, sig, key->key + ED25519_PUBLIC_KEY_OFFSET)) {
300
0
    OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SIGNATURE);
301
0
    return 0;
302
0
  }
303
304
0
  return 1;
305
0
}
306
307
}  // namespace
308
309
const EVP_PKEY_CTX_METHOD ed25519_pkey_meth = {
310
    /*pkey_id=*/EVP_PKEY_ED25519,
311
    /*init=*/nullptr,
312
    /*copy=*/pkey_ed25519_copy,
313
    /*cleanup=*/nullptr,
314
    /*keygen=*/pkey_ed25519_keygen,
315
    /*sign=*/nullptr,
316
    /*sign_message=*/pkey_ed25519_sign_message,
317
    /*verify=*/nullptr,
318
    /*verify_message=*/pkey_ed25519_verify_message,
319
    /*verify_recover=*/nullptr,
320
    /*encrypt=*/nullptr,
321
    /*decrypt=*/nullptr,
322
    /*derive=*/nullptr,
323
    /*paramgen=*/nullptr,
324
    /*ctrl=*/nullptr,
325
};
326
327
291k
const EVP_PKEY_ALG *EVP_pkey_ed25519(void) {
328
291k
  static const EVP_PKEY_ALG kAlg = {&ed25519_asn1_meth};
329
291k
  return &kAlg;
330
291k
}