1 /* $OpenBSD: gostr341001_key.c,v 1.8 2017/05/02 03:59:44 deraadt 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 GOSTerror(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 freezero(r, sizeof(GOST_KEY)); 109 } 110 111 int 112 GOST_KEY_check_key(const GOST_KEY *key) 113 { 114 int ok = 0; 115 BN_CTX *ctx = NULL; 116 BIGNUM *order = NULL; 117 EC_POINT *point = NULL; 118 119 if (key == NULL || key->group == NULL || key->pub_key == NULL) { 120 GOSTerror(ERR_R_PASSED_NULL_PARAMETER); 121 return 0; 122 } 123 if (EC_POINT_is_at_infinity(key->group, key->pub_key) != 0) { 124 GOSTerror(EC_R_POINT_AT_INFINITY); 125 goto err; 126 } 127 if ((ctx = BN_CTX_new()) == NULL) 128 goto err; 129 if ((point = EC_POINT_new(key->group)) == NULL) 130 goto err; 131 132 /* testing whether the pub_key is on the elliptic curve */ 133 if (EC_POINT_is_on_curve(key->group, key->pub_key, ctx) == 0) { 134 GOSTerror(EC_R_POINT_IS_NOT_ON_CURVE); 135 goto err; 136 } 137 /* testing whether pub_key * order is the point at infinity */ 138 if ((order = BN_new()) == NULL) 139 goto err; 140 if (EC_GROUP_get_order(key->group, order, ctx) == 0) { 141 GOSTerror(EC_R_INVALID_GROUP_ORDER); 142 goto err; 143 } 144 if (EC_POINT_mul(key->group, point, NULL, key->pub_key, order, 145 ctx) == 0) { 146 GOSTerror(ERR_R_EC_LIB); 147 goto err; 148 } 149 if (EC_POINT_is_at_infinity(key->group, point) == 0) { 150 GOSTerror(EC_R_WRONG_ORDER); 151 goto err; 152 } 153 /* 154 * in case the priv_key is present : check if generator * priv_key == 155 * pub_key 156 */ 157 if (key->priv_key != NULL) { 158 if (BN_cmp(key->priv_key, order) >= 0) { 159 GOSTerror(EC_R_WRONG_ORDER); 160 goto err; 161 } 162 if (EC_POINT_mul(key->group, point, key->priv_key, NULL, NULL, 163 ctx) == 0) { 164 GOSTerror(ERR_R_EC_LIB); 165 goto err; 166 } 167 if (EC_POINT_cmp(key->group, point, key->pub_key, ctx) != 0) { 168 GOSTerror(EC_R_INVALID_PRIVATE_KEY); 169 goto err; 170 } 171 } 172 ok = 1; 173 err: 174 BN_free(order); 175 BN_CTX_free(ctx); 176 EC_POINT_free(point); 177 return (ok); 178 } 179 180 int 181 GOST_KEY_set_public_key_affine_coordinates(GOST_KEY *key, BIGNUM *x, BIGNUM *y) 182 { 183 BN_CTX *ctx = NULL; 184 BIGNUM *tx, *ty; 185 EC_POINT *point = NULL; 186 int ok = 0; 187 188 if (key == NULL || key->group == NULL || x == NULL || y == NULL) { 189 GOSTerror(ERR_R_PASSED_NULL_PARAMETER); 190 return 0; 191 } 192 ctx = BN_CTX_new(); 193 if (ctx == NULL) 194 goto err; 195 196 point = EC_POINT_new(key->group); 197 if (point == NULL) 198 goto err; 199 200 if ((tx = BN_CTX_get(ctx)) == NULL) 201 goto err; 202 if ((ty = BN_CTX_get(ctx)) == NULL) 203 goto err; 204 if (EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, 205 ctx) == 0) 206 goto err; 207 if (EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, 208 ctx) == 0) 209 goto err; 210 /* 211 * Check if retrieved coordinates match originals: if not, values are 212 * out of range. 213 */ 214 if (BN_cmp(x, tx) != 0 || BN_cmp(y, ty) != 0) { 215 GOSTerror(EC_R_COORDINATES_OUT_OF_RANGE); 216 goto err; 217 } 218 if (GOST_KEY_set_public_key(key, point) == 0) 219 goto err; 220 221 if (GOST_KEY_check_key(key) == 0) 222 goto err; 223 224 ok = 1; 225 226 err: 227 EC_POINT_free(point); 228 BN_CTX_free(ctx); 229 return ok; 230 231 } 232 233 const EC_GROUP * 234 GOST_KEY_get0_group(const GOST_KEY *key) 235 { 236 return key->group; 237 } 238 239 int 240 GOST_KEY_set_group(GOST_KEY *key, const EC_GROUP *group) 241 { 242 EC_GROUP_free(key->group); 243 key->group = EC_GROUP_dup(group); 244 return (key->group == NULL) ? 0 : 1; 245 } 246 247 const BIGNUM * 248 GOST_KEY_get0_private_key(const GOST_KEY *key) 249 { 250 return key->priv_key; 251 } 252 253 int 254 GOST_KEY_set_private_key(GOST_KEY *key, const BIGNUM *priv_key) 255 { 256 BN_clear_free(key->priv_key); 257 key->priv_key = BN_dup(priv_key); 258 return (key->priv_key == NULL) ? 0 : 1; 259 } 260 261 const EC_POINT * 262 GOST_KEY_get0_public_key(const GOST_KEY *key) 263 { 264 return key->pub_key; 265 } 266 267 int 268 GOST_KEY_set_public_key(GOST_KEY *key, const EC_POINT *pub_key) 269 { 270 EC_POINT_free(key->pub_key); 271 key->pub_key = EC_POINT_dup(pub_key, key->group); 272 return (key->pub_key == NULL) ? 0 : 1; 273 } 274 275 int 276 GOST_KEY_get_digest(const GOST_KEY *key) 277 { 278 return key->digest_nid; 279 } 280 int 281 GOST_KEY_set_digest(GOST_KEY *key, int digest_nid) 282 { 283 if (digest_nid == NID_id_GostR3411_94_CryptoProParamSet || 284 digest_nid == NID_id_tc26_gost3411_2012_256 || 285 digest_nid == NID_id_tc26_gost3411_2012_512) { 286 key->digest_nid = digest_nid; 287 return 1; 288 } 289 290 return 0; 291 } 292 293 size_t 294 GOST_KEY_get_size(const GOST_KEY *r) 295 { 296 int i; 297 BIGNUM *order = NULL; 298 const EC_GROUP *group; 299 300 if (r == NULL) 301 return 0; 302 group = GOST_KEY_get0_group(r); 303 if (group == NULL) 304 return 0; 305 306 if ((order = BN_new()) == NULL) 307 return 0; 308 309 if (EC_GROUP_get_order(group, order, NULL) == 0) { 310 BN_clear_free(order); 311 return 0; 312 } 313 314 i = BN_num_bytes(order); 315 BN_clear_free(order); 316 return (i); 317 } 318 #endif 319