/src/opensc/openpace/src/misc.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2010-2012 Frank Morgner and Dominik Oepen |
3 | | * |
4 | | * This file is part of OpenPACE. |
5 | | * |
6 | | * OpenPACE is free software: you can redistribute it and/or modify it under |
7 | | * the terms of the GNU General Public License as published by the Free |
8 | | * Software Foundation, either version 3 of the License, or (at your option) |
9 | | * any later version. |
10 | | * |
11 | | * OpenPACE is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
13 | | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
14 | | * details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License along with |
17 | | * OpenPACE. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * Additional permission under GNU GPL version 3 section 7 |
20 | | * |
21 | | * If you modify this Program, or any covered work, by linking or combining it |
22 | | * with OpenSSL (or a modified version of that library), containing |
23 | | * parts covered by the terms of OpenSSL's license, the licensors of |
24 | | * this Program grant you additional permission to convey the resulting work. |
25 | | * Corresponding Source for a non-source form of such a combination shall include |
26 | | * the source code for the parts of OpenSSL used as well as that of the |
27 | | * covered work. |
28 | | * |
29 | | * If you modify this Program, or any covered work, by linking or combining it |
30 | | * with OpenSC (or a modified version of that library), containing |
31 | | * parts covered by the terms of OpenSC's license, the licensors of |
32 | | * this Program grant you additional permission to convey the resulting work. |
33 | | * Corresponding Source for a non-source form of such a combination shall include |
34 | | * the source code for the parts of OpenSC used as well as that of the |
35 | | * covered work. |
36 | | */ |
37 | | |
38 | | /** |
39 | | * @file misc.c |
40 | | * @brief Miscellaneous functions used in OpenPACE |
41 | | * |
42 | | * @author Frank Morgner <frankmorgner@gmail.com> |
43 | | * @author Dominik Oepen <oepen@informatik.hu-berlin.de> |
44 | | */ |
45 | | |
46 | | #ifdef HAVE_CONFIG_H |
47 | | #include "config.h" |
48 | | #endif |
49 | | |
50 | | #include "eac_err.h" |
51 | | #include "misc.h" |
52 | | #include <limits.h> |
53 | | #include <openssl/ecdh.h> |
54 | | #include <openssl/ecdsa.h> |
55 | | #include <openssl/ossl_typ.h> |
56 | | #include <stdint.h> |
57 | | #include <string.h> |
58 | | |
59 | | static int ecdh_compute_key_point(void *out, size_t outlen, const EC_POINT *pub_key, |
60 | | EC_KEY *ecdh, |
61 | | void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)); |
62 | | static int new_ecdh_compute_key_point(unsigned char **psec, size_t *pseclen, |
63 | | const EC_POINT *pub_key, const EC_KEY *ecdh); |
64 | | |
65 | | struct ec_key_method_st { |
66 | | const char *name; |
67 | | int32_t flags; |
68 | | int (*init)(EC_KEY *key); |
69 | | void (*finish)(EC_KEY *key); |
70 | | int (*copy)(EC_KEY *dest, const EC_KEY *src); |
71 | | int (*set_group)(EC_KEY *key, const EC_GROUP *grp); |
72 | | int (*set_private)(EC_KEY *key, const BIGNUM *priv_key); |
73 | | int (*set_public)(EC_KEY *key, const EC_POINT *pub_key); |
74 | | int (*keygen)(EC_KEY *key); |
75 | | int (*compute_key)(unsigned char **pout, size_t *poutlen, |
76 | | const EC_POINT *pub_key, const EC_KEY *ecdh); |
77 | | int (*sign)(int type, const unsigned char *dgst, int dlen, unsigned char |
78 | | *sig, unsigned int *siglen, const BIGNUM *kinv, |
79 | | const BIGNUM *r, EC_KEY *eckey); |
80 | | int (*sign_setup)(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, |
81 | | BIGNUM **rp); |
82 | | ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgst_len, |
83 | | const BIGNUM *in_kinv, const BIGNUM *in_r, |
84 | | EC_KEY *eckey); |
85 | | |
86 | | int (*verify)(int type, const unsigned char *dgst, int dgst_len, |
87 | | const unsigned char *sigbuf, int sig_len, EC_KEY *eckey); |
88 | | int (*verify_sig)(const unsigned char *dgst, int dgst_len, |
89 | | const ECDSA_SIG *sig, EC_KEY *eckey); |
90 | | }; |
91 | | |
92 | | struct ecdh_method |
93 | | { |
94 | | const char *name; |
95 | | int (*compute_key)(void *key, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh, |
96 | | void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)); |
97 | | #if 0 |
98 | | int (*init)(EC_KEY *eckey); |
99 | | int (*finish)(EC_KEY *eckey); |
100 | | #endif |
101 | | int flags; |
102 | | char *app_data; |
103 | | }; |
104 | | |
105 | | #ifdef HAVE_EC_KEY_METHOD |
106 | | |
107 | | static const EC_KEY_METHOD openssl_ec_key_meth_point = { |
108 | | "OpenSSL EC_KEY method with Point", |
109 | | 0, |
110 | | 0,0,0,0,0,0, |
111 | | NULL, |
112 | | new_ecdh_compute_key_point, |
113 | | NULL, |
114 | | NULL, |
115 | | NULL, |
116 | | NULL, |
117 | | NULL |
118 | | }; |
119 | | |
120 | | const EC_KEY_METHOD *EC_KEY_OpenSSL_Point(void) |
121 | 0 | { |
122 | 0 | return &openssl_ec_key_meth_point; |
123 | 0 | } |
124 | | |
125 | | #else |
126 | | |
127 | | static ECDH_METHOD openssl_ecdh_meth_point = { |
128 | | "OpenSSL ECDH method with Point", |
129 | | ecdh_compute_key_point, |
130 | | #if 0 |
131 | | NULL, /* init */ |
132 | | NULL, /* finish */ |
133 | | #endif |
134 | | 0, /* flags */ |
135 | | NULL /* app_data */ |
136 | | }; |
137 | | |
138 | | const ECDH_METHOD *ECDH_OpenSSL_Point(void) |
139 | | { |
140 | | return &openssl_ecdh_meth_point; |
141 | | } |
142 | | #endif |
143 | | |
144 | | int new_ecdh_compute_key_point(unsigned char **psec, size_t *pseclen, const |
145 | | EC_POINT *pub_key, const EC_KEY *ecdh) |
146 | 0 | { |
147 | | /* The new API requires us to allocate the memory for the output buffer */ |
148 | 0 | int ret= -1; |
149 | | /* should be enough to hold an uncompressed point of a 528 bit curve |
150 | | * (e.g. secp521r1, which is the biggest curve of BSI TR-03110) */ |
151 | 0 | *psec = OPENSSL_malloc(133); |
152 | 0 | check(*psec, "Out of memory"); |
153 | 0 | *pseclen = 133; |
154 | 0 | ret = ecdh_compute_key_point(*psec, *pseclen, pub_key, (EC_KEY *) ecdh, NULL); |
155 | 0 | err: |
156 | 0 | if (ret <= 0) { |
157 | 0 | OPENSSL_free(*psec); |
158 | 0 | *psec = NULL; |
159 | 0 | *pseclen = 0; |
160 | 0 | ret = 0; |
161 | 0 | } else { |
162 | 0 | *pseclen = ret; |
163 | 0 | ret = 1; |
164 | 0 | } |
165 | 0 | return ret; |
166 | 0 | } |
167 | | |
168 | | int ecdh_compute_key_point(void *out, size_t outlen, const EC_POINT *pub_key, |
169 | | EC_KEY *ecdh, |
170 | | void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen)) |
171 | 0 | { |
172 | | /* The old API allocates the memory for us */ |
173 | 0 | BN_CTX *ctx = NULL; |
174 | 0 | EC_POINT *tmp=NULL; |
175 | 0 | const BIGNUM *priv_key; |
176 | 0 | const EC_GROUP* group; |
177 | 0 | int ret= -1; |
178 | 0 | size_t buflen; |
179 | 0 | unsigned char *buf=NULL; |
180 | |
|
181 | 0 | check((outlen < INT_MAX), "out of memory"); /* sort of, anyway */ |
182 | |
|
183 | 0 | if ((ctx = BN_CTX_new()) == NULL) goto err; |
184 | 0 | BN_CTX_start(ctx); |
185 | |
|
186 | 0 | priv_key = EC_KEY_get0_private_key(ecdh); |
187 | 0 | check(priv_key, "No pivate key"); |
188 | |
|
189 | 0 | group = EC_KEY_get0_group(ecdh); |
190 | 0 | tmp = EC_POINT_new(group); |
191 | 0 | check(tmp, "Out of memory"); |
192 | |
|
193 | 0 | check((EC_POINT_mul(group, tmp, NULL, pub_key, priv_key, ctx)), |
194 | 0 | "Arithmetic error"); |
195 | |
|
196 | 0 | buflen = EC_POINT_point2oct(group, tmp, EC_KEY_get_conv_form(ecdh), NULL, |
197 | 0 | 0, ctx); |
198 | 0 | check((buflen != 0), "Failed to convert point to hex"); |
199 | |
|
200 | 0 | buf = OPENSSL_malloc(buflen); |
201 | 0 | check(buf, "Out of memory"); |
202 | |
|
203 | 0 | check((buflen == EC_POINT_point2oct(group, tmp, EC_KEY_get_conv_form(ecdh), |
204 | 0 | buf, buflen, ctx)), "Failed to convert point to hex"); |
205 | |
|
206 | 0 | if (KDF != 0) |
207 | 0 | { |
208 | 0 | check((KDF(buf, buflen, out, &outlen) != NULL), |
209 | 0 | "Key derivation function failed"); |
210 | 0 | ret = outlen; |
211 | 0 | } |
212 | 0 | else |
213 | 0 | { |
214 | | /* no KDF, just copy as much as we can */ |
215 | 0 | if (outlen > buflen) |
216 | 0 | outlen = buflen; |
217 | 0 | memcpy(out, buf, outlen); |
218 | 0 | ret = outlen; |
219 | 0 | } |
220 | | |
221 | 0 | err: |
222 | 0 | if (tmp) EC_POINT_free(tmp); |
223 | 0 | if (ctx) BN_CTX_end(ctx); |
224 | 0 | if (ctx) BN_CTX_free(ctx); |
225 | 0 | if (buf) OPENSSL_free(buf); |
226 | 0 | return(ret); |
227 | 0 | } |
228 | | |
229 | | BUF_MEM * |
230 | | BUF_MEM_create(size_t len) |
231 | 0 | { |
232 | 0 | BUF_MEM *out = BUF_MEM_new(); |
233 | 0 | if (!out) |
234 | 0 | return NULL; |
235 | | |
236 | 0 | if (len == 0) |
237 | 0 | return out; |
238 | | |
239 | 0 | if (!BUF_MEM_grow(out, len)) { |
240 | 0 | BUF_MEM_free(out); |
241 | 0 | return NULL; |
242 | 0 | } |
243 | | |
244 | 0 | return out; |
245 | 0 | } |
246 | | |
247 | | BUF_MEM * |
248 | | BUF_MEM_create_init(const void *buf, size_t len) |
249 | 0 | { |
250 | 0 | BUF_MEM *out; |
251 | |
|
252 | 0 | out = BUF_MEM_create(len); |
253 | 0 | if (!out) |
254 | 0 | return NULL; |
255 | | |
256 | 0 | memcpy(out->data, buf, len); |
257 | |
|
258 | 0 | return out; |
259 | 0 | } |
260 | | |
261 | | BUF_MEM * |
262 | | BUF_MEM_dup(const BUF_MEM * in) |
263 | 0 | { |
264 | 0 | BUF_MEM * out = NULL; |
265 | |
|
266 | 0 | if (!in) |
267 | 0 | return NULL; |
268 | | |
269 | 0 | out = BUF_MEM_create(in->length); |
270 | 0 | check(out, "Failed to allocate memory"); |
271 | |
|
272 | 0 | memcpy(out->data, in->data, in->length); |
273 | 0 | out->max = in->max; |
274 | |
|
275 | 0 | err: |
276 | 0 | return out; |
277 | 0 | } |
278 | | |
279 | | BUF_MEM * |
280 | | BN_bn2buf(const BIGNUM *bn) |
281 | 0 | { |
282 | 0 | BUF_MEM * out; |
283 | |
|
284 | 0 | if (!bn) |
285 | 0 | return NULL; |
286 | | |
287 | 0 | out = BUF_MEM_create(BN_num_bytes(bn)); |
288 | 0 | if (!out) |
289 | 0 | return NULL; |
290 | | |
291 | 0 | out->length = BN_bn2bin(bn, (unsigned char *) out->data); |
292 | |
|
293 | 0 | return out; |
294 | 0 | } |
295 | | |
296 | | BUF_MEM * |
297 | | EC_POINT_point2mem(const EC_KEY * ecdh, BN_CTX * bn_ctx, const EC_POINT * ecp) |
298 | 0 | { |
299 | 0 | size_t len; |
300 | 0 | BUF_MEM * out; |
301 | |
|
302 | 0 | if (!ecp) |
303 | 0 | return NULL; |
304 | | |
305 | 0 | len = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), ecp, |
306 | 0 | EC_KEY_get_conv_form(ecdh), NULL, 0, bn_ctx); |
307 | 0 | if (len == 0) |
308 | 0 | return NULL; |
309 | | |
310 | 0 | out = BUF_MEM_create(len); |
311 | 0 | if (!out) |
312 | 0 | return NULL; |
313 | | |
314 | 0 | out->length = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), ecp, |
315 | 0 | EC_KEY_get_conv_form(ecdh), (unsigned char *) out->data, out->max, |
316 | 0 | bn_ctx); |
317 | |
|
318 | 0 | return out; |
319 | 0 | } |