1 /* $OpenBSD: gostr341001_key.c,v 1.5 2015/02/14 06:40:04 jsing Exp $ */ 2 /* 3 * Copyright (c) 2014 Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 4 * Copyright (c) 2005-2006 Cryptocom LTD 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 18 * 3. All advertising materials mentioning features or use of this 19 * software must display the following acknowledgment: 20 * "This product includes software developed by the OpenSSL Project 21 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 22 * 23 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 24 * endorse or promote products derived from this software without 25 * prior written permission. For written permission, please contact 26 * openssl-core@openssl.org. 27 * 28 * 5. Products derived from this software may not be called "OpenSSL" 29 * nor may "OpenSSL" appear in their names without prior written 30 * permission of the OpenSSL Project. 31 * 32 * 6. Redistributions of any form whatsoever must retain the following 33 * acknowledgment: 34 * "This product includes software developed by the OpenSSL Project 35 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 36 * 37 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 38 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 40 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 43 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 48 * OF THE POSSIBILITY OF SUCH DAMAGE. 49 * ==================================================================== 50 */ 51 52 #include <string.h> 53 54 #include <openssl/opensslconf.h> 55 56 #ifndef OPENSSL_NO_GOST 57 #include <openssl/bn.h> 58 #include <openssl/err.h> 59 #include <openssl/gost.h> 60 #include <openssl/objects.h> 61 #include "gost_locl.h" 62 63 struct gost_key_st { 64 EC_GROUP *group; 65 66 EC_POINT *pub_key; 67 BIGNUM *priv_key; 68 69 int references; 70 71 int digest_nid; 72 }; 73 74 GOST_KEY * 75 GOST_KEY_new(void) 76 { 77 GOST_KEY *ret; 78 79 ret = malloc(sizeof(GOST_KEY)); 80 if (ret == NULL) { 81 GOSTerr(GOST_F_GOST_KEY_NEW, ERR_R_MALLOC_FAILURE); 82 return (NULL); 83 } 84 ret->group = NULL; 85 ret->pub_key = NULL; 86 ret->priv_key = NULL; 87 ret->references = 1; 88 ret->digest_nid = NID_undef; 89 return (ret); 90 } 91 92 void 93 GOST_KEY_free(GOST_KEY *r) 94 { 95 int i; 96 97 if (r == NULL) 98 return; 99 100 i = CRYPTO_add(&r->references, -1, CRYPTO_LOCK_EC); 101 if (i > 0) 102 return; 103 104 EC_GROUP_free(r->group); 105 EC_POINT_free(r->pub_key); 106 BN_clear_free(r->priv_key); 107 108 explicit_bzero((void *)r, sizeof(GOST_KEY)); 109 free(r); 110 } 111 112 int 113 GOST_KEY_check_key(const GOST_KEY *key) 114 { 115 int ok = 0; 116 BN_CTX *ctx = NULL; 117 BIGNUM *order = NULL; 118 EC_POINT *point = NULL; 119 120 if (key == NULL || key->group == NULL || key->pub_key == NULL) { 121 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, ERR_R_PASSED_NULL_PARAMETER); 122 return 0; 123 } 124 if (EC_POINT_is_at_infinity(key->group, key->pub_key) != 0) { 125 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, EC_R_POINT_AT_INFINITY); 126 goto err; 127 } 128 if ((ctx = BN_CTX_new()) == NULL) 129 goto err; 130 if ((point = EC_POINT_new(key->group)) == NULL) 131 goto err; 132 133 /* testing whether the pub_key is on the elliptic curve */ 134 if (EC_POINT_is_on_curve(key->group, key->pub_key, ctx) == 0) { 135 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, EC_R_POINT_IS_NOT_ON_CURVE); 136 goto err; 137 } 138 /* testing whether pub_key * order is the point at infinity */ 139 if ((order = BN_new()) == NULL) 140 goto err; 141 if (EC_GROUP_get_order(key->group, order, ctx) == 0) { 142 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, EC_R_INVALID_GROUP_ORDER); 143 goto err; 144 } 145 if (EC_POINT_mul(key->group, point, NULL, key->pub_key, order, 146 ctx) == 0) { 147 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, ERR_R_EC_LIB); 148 goto err; 149 } 150 if (EC_POINT_is_at_infinity(key->group, point) == 0) { 151 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, EC_R_WRONG_ORDER); 152 goto err; 153 } 154 /* 155 * in case the priv_key is present : check if generator * priv_key == 156 * pub_key 157 */ 158 if (key->priv_key != NULL) { 159 if (BN_cmp(key->priv_key, order) >= 0) { 160 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, EC_R_WRONG_ORDER); 161 goto err; 162 } 163 if (EC_POINT_mul(key->group, point, key->priv_key, NULL, NULL, 164 ctx) == 0) { 165 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, ERR_R_EC_LIB); 166 goto err; 167 } 168 if (EC_POINT_cmp(key->group, point, key->pub_key, ctx) != 0) { 169 GOSTerr(GOST_F_GOST_KEY_CHECK_KEY, 170 EC_R_INVALID_PRIVATE_KEY); 171 goto err; 172 } 173 } 174 ok = 1; 175 err: 176 BN_free(order); 177 BN_CTX_free(ctx); 178 EC_POINT_free(point); 179 return (ok); 180 } 181 182 int 183 GOST_KEY_set_public_key_affine_coordinates(GOST_KEY *key, BIGNUM *x, BIGNUM *y) 184 { 185 BN_CTX *ctx = NULL; 186 BIGNUM *tx, *ty; 187 EC_POINT *point = NULL; 188 int ok = 0; 189 190 if (key == NULL || key->group == NULL || x == NULL || y == NULL) { 191 GOSTerr(GOST_F_GOST_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES, 192 ERR_R_PASSED_NULL_PARAMETER); 193 return 0; 194 } 195 ctx = BN_CTX_new(); 196 if (ctx == NULL) 197 goto err; 198 199 point = EC_POINT_new(key->group); 200 if (point == NULL) 201 goto err; 202 203 if ((tx = BN_CTX_get(ctx)) == NULL) 204 goto err; 205 if ((ty = BN_CTX_get(ctx)) == NULL) 206 goto err; 207 if (EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, 208 ctx) == 0) 209 goto err; 210 if (EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, 211 ctx) == 0) 212 goto err; 213 /* 214 * Check if retrieved coordinates match originals: if not, values are 215 * out of range. 216 */ 217 if (BN_cmp(x, tx) != 0 || BN_cmp(y, ty) != 0) { 218 GOSTerr(GOST_F_GOST_KEY_SET_PUBLIC_KEY_AFFINE_COORDINATES, 219 EC_R_COORDINATES_OUT_OF_RANGE); 220 goto err; 221 } 222 if (GOST_KEY_set_public_key(key, point) == 0) 223 goto err; 224 225 if (GOST_KEY_check_key(key) == 0) 226 goto err; 227 228 ok = 1; 229 230 err: 231 EC_POINT_free(point); 232 BN_CTX_free(ctx); 233 return ok; 234 235 } 236 237 const EC_GROUP * 238 GOST_KEY_get0_group(const GOST_KEY *key) 239 { 240 return key->group; 241 } 242 243 int 244 GOST_KEY_set_group(GOST_KEY *key, const EC_GROUP *group) 245 { 246 EC_GROUP_free(key->group); 247 key->group = EC_GROUP_dup(group); 248 return (key->group == NULL) ? 0 : 1; 249 } 250 251 const BIGNUM * 252 GOST_KEY_get0_private_key(const GOST_KEY *key) 253 { 254 return key->priv_key; 255 } 256 257 int 258 GOST_KEY_set_private_key(GOST_KEY *key, const BIGNUM *priv_key) 259 { 260 BN_clear_free(key->priv_key); 261 key->priv_key = BN_dup(priv_key); 262 return (key->priv_key == NULL) ? 0 : 1; 263 } 264 265 const EC_POINT * 266 GOST_KEY_get0_public_key(const GOST_KEY *key) 267 { 268 return key->pub_key; 269 } 270 271 int 272 GOST_KEY_set_public_key(GOST_KEY *key, const EC_POINT *pub_key) 273 { 274 EC_POINT_free(key->pub_key); 275 key->pub_key = EC_POINT_dup(pub_key, key->group); 276 return (key->pub_key == NULL) ? 0 : 1; 277 } 278 279 int 280 GOST_KEY_get_digest(const GOST_KEY *key) 281 { 282 return key->digest_nid; 283 } 284 int 285 GOST_KEY_set_digest(GOST_KEY *key, int digest_nid) 286 { 287 if (digest_nid == NID_id_GostR3411_94_CryptoProParamSet || 288 digest_nid == NID_id_tc26_gost3411_2012_256 || 289 digest_nid == NID_id_tc26_gost3411_2012_512) { 290 key->digest_nid = digest_nid; 291 return 1; 292 } 293 294 return 0; 295 } 296 297 size_t 298 GOST_KEY_get_size(const GOST_KEY *r) 299 { 300 int i; 301 BIGNUM *order = NULL; 302 const EC_GROUP *group; 303 304 if (r == NULL) 305 return 0; 306 group = GOST_KEY_get0_group(r); 307 if (group == NULL) 308 return 0; 309 310 if ((order = BN_new()) == NULL) 311 return 0; 312 313 if (EC_GROUP_get_order(group, order, NULL) == 0) { 314 BN_clear_free(order); 315 return 0; 316 } 317 318 i = BN_num_bytes(order); 319 BN_clear_free(order); 320 return (i); 321 } 322 #endif 323