diff options
author | tb <> | 2024-11-08 22:03:29 +0000 |
---|---|---|
committer | tb <> | 2024-11-08 22:03:29 +0000 |
commit | 6b42101493f1f270e3e232e576ceb26a05cede5f (patch) | |
tree | 1f231b14e5b71cd9d8f6a4e9080686d27596eb99 /src/lib | |
parent | 87e01b19e22b5aa813af998b149eb34fd96de895 (diff) | |
download | openbsd-6b42101493f1f270e3e232e576ceb26a05cede5f.tar.gz openbsd-6b42101493f1f270e3e232e576ceb26a05cede5f.tar.bz2 openbsd-6b42101493f1f270e3e232e576ceb26a05cede5f.zip |
Sweep over EC_KEY_copy()
This is a special snowflake. Its logic is such that it only overwrites
things on the target that are available in the source. So if the source
has no group (yes, that's possible), the destination's group will remain.
Even better: if you copy a public key over what was previously a private
key, the private scalar will remain. That's almost never going to result
in a valid key. If you copy from a larger group to a smaller group the
private scalar will most likely be out of range [1, order).
Use dup functions instead of reimplementing badly and add a snarky comment
courtesy of beck to one of those silly const annotations (there's a small
addendum by me).
ok beck jsing
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/ec/ec_key.c | 60 |
1 files changed, 28 insertions, 32 deletions
diff --git a/src/lib/libcrypto/ec/ec_key.c b/src/lib/libcrypto/ec/ec_key.c index 753ababa31..4f3f27dabd 100644 --- a/src/lib/libcrypto/ec/ec_key.c +++ b/src/lib/libcrypto/ec/ec_key.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ec_key.c,v 1.44 2024/11/08 21:56:58 tb Exp $ */ | 1 | /* $OpenBSD: ec_key.c,v 1.45 2024/11/08 22:03:29 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Written by Nils Larsch for the OpenSSL project. | 3 | * Written by Nils Larsch for the OpenSSL project. |
4 | */ | 4 | */ |
@@ -132,58 +132,54 @@ EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) | |||
132 | ECerror(ERR_R_PASSED_NULL_PARAMETER); | 132 | ECerror(ERR_R_PASSED_NULL_PARAMETER); |
133 | return NULL; | 133 | return NULL; |
134 | } | 134 | } |
135 | |||
135 | if (src->meth != dest->meth) { | 136 | if (src->meth != dest->meth) { |
136 | if (dest->meth != NULL && dest->meth->finish != NULL) | 137 | if (dest->meth != NULL && dest->meth->finish != NULL) |
137 | dest->meth->finish(dest); | 138 | dest->meth->finish(dest); |
138 | } | 139 | } |
139 | /* copy the parameters */ | 140 | |
140 | if (src->group) { | 141 | if (src->group != NULL) { |
141 | const EC_METHOD *meth = src->group->meth; | ||
142 | /* clear the old group */ | ||
143 | EC_GROUP_free(dest->group); | 142 | EC_GROUP_free(dest->group); |
144 | dest->group = EC_GROUP_new(meth); | 143 | if ((dest->group = EC_GROUP_dup(src->group)) == NULL) |
145 | if (dest->group == NULL) | ||
146 | return NULL; | ||
147 | if (!EC_GROUP_copy(dest->group, src->group)) | ||
148 | return NULL; | ||
149 | } | ||
150 | /* copy the public key */ | ||
151 | if (src->pub_key && src->group) { | ||
152 | EC_POINT_free(dest->pub_key); | ||
153 | dest->pub_key = EC_POINT_new(src->group); | ||
154 | if (dest->pub_key == NULL) | ||
155 | return NULL; | 144 | return NULL; |
156 | if (!EC_POINT_copy(dest->pub_key, src->pub_key)) | 145 | if (src->pub_key != NULL) { |
157 | return NULL; | 146 | EC_POINT_free(dest->pub_key); |
158 | } | 147 | if ((dest->pub_key = EC_POINT_dup(src->pub_key, |
159 | /* copy the private key */ | 148 | src->group)) == NULL) |
160 | if (src->priv_key) { | ||
161 | if (dest->priv_key == NULL) { | ||
162 | dest->priv_key = BN_new(); | ||
163 | if (dest->priv_key == NULL) | ||
164 | return NULL; | 149 | return NULL; |
165 | } | 150 | } |
166 | if (!bn_copy(dest->priv_key, src->priv_key)) | 151 | } |
152 | |||
153 | /* | ||
154 | * XXX - if there's no priv_key on src, dest retains its probably | ||
155 | * invalid priv_key. This makes no sense. Can we change this? | ||
156 | */ | ||
157 | if (src->priv_key != NULL) { | ||
158 | BN_free(dest->priv_key); | ||
159 | if ((dest->priv_key = BN_dup(src->priv_key)) == NULL) | ||
167 | return NULL; | 160 | return NULL; |
168 | } | 161 | } |
169 | 162 | ||
170 | /* copy the rest */ | ||
171 | dest->enc_flag = src->enc_flag; | 163 | dest->enc_flag = src->enc_flag; |
172 | dest->conv_form = src->conv_form; | 164 | dest->conv_form = src->conv_form; |
173 | dest->version = src->version; | 165 | dest->version = src->version; |
174 | dest->flags = src->flags; | 166 | dest->flags = src->flags; |
175 | 167 | ||
168 | /* | ||
169 | * The fun part about being a toolkit implementer is that the rest of | ||
170 | * the world gets to live with your terrible API design choices for | ||
171 | * eternity. (To be fair: the signature was changed in OpenSSL 3). | ||
172 | */ | ||
176 | if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY, &dest->ex_data, | 173 | if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_EC_KEY, &dest->ex_data, |
177 | &((EC_KEY *)src)->ex_data)) /* XXX const */ | 174 | &((EC_KEY *)src)->ex_data)) /* XXX const */ |
178 | return NULL; | 175 | return NULL; |
179 | 176 | ||
180 | if (src->meth != dest->meth) { | 177 | dest->meth = src->meth; |
181 | dest->meth = src->meth; | ||
182 | } | ||
183 | 178 | ||
184 | if (src->meth != NULL && src->meth->copy != NULL && | 179 | if (src->meth != NULL && src->meth->copy != NULL) { |
185 | src->meth->copy(dest, src) == 0) | 180 | if (!src->meth->copy(dest, src)) |
186 | return 0; | 181 | return NULL; |
182 | } | ||
187 | 183 | ||
188 | return dest; | 184 | return dest; |
189 | } | 185 | } |