/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 | } |