]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved | |
4 | * | |
5 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
6 | * this file except in compliance with the License. You can obtain a copy | |
7 | * in the file LICENSE in the source distribution or at | |
8 | * https://www.openssl.org/source/license.html | |
9 | */ | |
10 | ||
11 | /* | |
12 | * ECDH low level APIs are deprecated for public use, but still ok for | |
13 | * internal use. | |
14 | */ | |
15 | #include "internal/deprecated.h" | |
16 | ||
17 | #include <string.h> | |
18 | #include <limits.h> | |
19 | ||
20 | #include "internal/cryptlib.h" | |
21 | ||
22 | #include <openssl/err.h> | |
23 | #include <openssl/bn.h> | |
24 | #include <openssl/objects.h> | |
25 | #include <openssl/ec.h> | |
26 | #include "ec_local.h" | |
27 | ||
28 | int ossl_ecdh_compute_key(unsigned char **psec, size_t *pseclen, | |
29 | const EC_POINT *pub_key, const EC_KEY *ecdh) | |
30 | { | |
31 | if (ecdh->group->meth->ecdh_compute_key == NULL) { | |
32 | ERR_raise(ERR_LIB_EC, EC_R_CURVE_DOES_NOT_SUPPORT_ECDH); | |
33 | return 0; | |
34 | } | |
35 | ||
36 | return ecdh->group->meth->ecdh_compute_key(psec, pseclen, pub_key, ecdh); | |
37 | } | |
38 | ||
39 | /*- | |
40 | * This implementation is based on the following primitives in the | |
41 | * IEEE 1363 standard: | |
42 | * - ECKAS-DH1 | |
43 | * - ECSVDP-DH | |
44 | * | |
45 | * It also conforms to SP800-56A r3 | |
46 | * See Section 5.7.1.2 "Elliptic Curve Cryptography Cofactor Diffie-Hellman | |
47 | * (ECC CDH) Primitive:". The steps listed below refer to SP800-56A. | |
48 | */ | |
49 | int ossl_ecdh_simple_compute_key(unsigned char **pout, size_t *poutlen, | |
50 | const EC_POINT *pub_key, const EC_KEY *ecdh) | |
51 | { | |
52 | BN_CTX *ctx; | |
53 | EC_POINT *tmp = NULL; | |
54 | BIGNUM *x = NULL; | |
55 | const BIGNUM *priv_key; | |
56 | const EC_GROUP *group; | |
57 | int ret = 0; | |
58 | size_t buflen, len; | |
59 | unsigned char *buf = NULL; | |
60 | ||
61 | if ((ctx = BN_CTX_new_ex(ecdh->libctx)) == NULL) | |
62 | goto err; | |
63 | BN_CTX_start(ctx); | |
64 | x = BN_CTX_get(ctx); | |
65 | if (x == NULL) { | |
66 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); | |
67 | goto err; | |
68 | } | |
69 | ||
70 | priv_key = EC_KEY_get0_private_key(ecdh); | |
71 | if (priv_key == NULL) { | |
72 | ERR_raise(ERR_LIB_EC, EC_R_MISSING_PRIVATE_KEY); | |
73 | goto err; | |
74 | } | |
75 | ||
76 | group = EC_KEY_get0_group(ecdh); | |
77 | ||
78 | /* | |
79 | * Step(1) - Compute the point tmp = cofactor * owners_private_key | |
80 | * * peer_public_key. | |
81 | */ | |
82 | if (EC_KEY_get_flags(ecdh) & EC_FLAG_COFACTOR_ECDH) { | |
83 | if (!EC_GROUP_get_cofactor(group, x, NULL) || | |
84 | !BN_mul(x, x, priv_key, ctx)) { | |
85 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); | |
86 | goto err; | |
87 | } | |
88 | priv_key = x; | |
89 | } | |
90 | ||
91 | if ((tmp = EC_POINT_new(group)) == NULL) { | |
92 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); | |
93 | goto err; | |
94 | } | |
95 | ||
96 | if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv_key, ctx)) { | |
97 | ERR_raise(ERR_LIB_EC, EC_R_POINT_ARITHMETIC_FAILURE); | |
98 | goto err; | |
99 | } | |
100 | ||
101 | /* | |
102 | * Step(2) : If point tmp is at infinity then clear intermediate values and | |
103 | * exit. Note: getting affine coordinates returns 0 if point is at infinity. | |
104 | * Step(3a) : Get x-coordinate of point x = tmp.x | |
105 | */ | |
106 | if (!EC_POINT_get_affine_coordinates(group, tmp, x, NULL, ctx)) { | |
107 | ERR_raise(ERR_LIB_EC, EC_R_POINT_ARITHMETIC_FAILURE); | |
108 | goto err; | |
109 | } | |
110 | ||
111 | /* | |
112 | * Step(3b) : convert x to a byte string, using the field-element-to-byte | |
113 | * string conversion routine defined in Appendix C.2 | |
114 | */ | |
115 | buflen = (EC_GROUP_get_degree(group) + 7) / 8; | |
116 | len = BN_num_bytes(x); | |
117 | if (len > buflen) { | |
118 | ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR); | |
119 | goto err; | |
120 | } | |
121 | if ((buf = OPENSSL_malloc(buflen)) == NULL) { | |
122 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); | |
123 | goto err; | |
124 | } | |
125 | ||
126 | memset(buf, 0, buflen - len); | |
127 | if (len != (size_t)BN_bn2bin(x, buf + buflen - len)) { | |
128 | ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB); | |
129 | goto err; | |
130 | } | |
131 | ||
132 | *pout = buf; | |
133 | *poutlen = buflen; | |
134 | buf = NULL; | |
135 | ||
136 | ret = 1; | |
137 | ||
138 | err: | |
139 | /* Step(4) : Destroy all intermediate calculations */ | |
140 | BN_clear(x); | |
141 | EC_POINT_clear_free(tmp); | |
142 | BN_CTX_end(ctx); | |
143 | BN_CTX_free(ctx); | |
144 | OPENSSL_free(buf); | |
145 | return ret; | |
146 | } |