x_pubkey.c revision 296465
1/* crypto/asn1/x_pubkey.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59#include <stdio.h> 60#include "cryptlib.h" 61#include <openssl/asn1t.h> 62#include <openssl/x509.h> 63#ifndef OPENSSL_NO_RSA 64# include <openssl/rsa.h> 65#endif 66#ifndef OPENSSL_NO_DSA 67# include <openssl/dsa.h> 68#endif 69 70/* Minor tweak to operation: free up EVP_PKEY */ 71static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it) 72{ 73 if (operation == ASN1_OP_FREE_POST) { 74 X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; 75 EVP_PKEY_free(pubkey->pkey); 76 } 77 return 1; 78} 79 80ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { 81 ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), 82 ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) 83} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) 84 85IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) 86 87int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) 88{ 89 X509_PUBKEY *pk = NULL; 90 X509_ALGOR *a; 91 ASN1_OBJECT *o; 92 unsigned char *s, *p = NULL; 93 int i; 94 95 if (x == NULL) 96 return (0); 97 98 if ((pk = X509_PUBKEY_new()) == NULL) 99 goto err; 100 a = pk->algor; 101 102 /* set the algorithm id */ 103 if ((o = OBJ_nid2obj(pkey->type)) == NULL) 104 goto err; 105 ASN1_OBJECT_free(a->algorithm); 106 a->algorithm = o; 107 108 /* Set the parameter list */ 109 if (!pkey->save_parameters || (pkey->type == EVP_PKEY_RSA)) { 110 if ((a->parameter == NULL) || (a->parameter->type != V_ASN1_NULL)) { 111 ASN1_TYPE_free(a->parameter); 112 if (!(a->parameter = ASN1_TYPE_new())) { 113 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 114 goto err; 115 } 116 a->parameter->type = V_ASN1_NULL; 117 } 118 } 119#ifndef OPENSSL_NO_DSA 120 else if (pkey->type == EVP_PKEY_DSA) { 121 unsigned char *pp; 122 DSA *dsa; 123 124 dsa = pkey->pkey.dsa; 125 dsa->write_params = 0; 126 ASN1_TYPE_free(a->parameter); 127 if ((i = i2d_DSAparams(dsa, NULL)) <= 0) 128 goto err; 129 if (!(p = (unsigned char *)OPENSSL_malloc(i))) { 130 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 131 goto err; 132 } 133 pp = p; 134 i2d_DSAparams(dsa, &pp); 135 if (!(a->parameter = ASN1_TYPE_new())) { 136 OPENSSL_free(p); 137 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 138 goto err; 139 } 140 a->parameter->type = V_ASN1_SEQUENCE; 141 if (!(a->parameter->value.sequence = ASN1_STRING_new())) { 142 OPENSSL_free(p); 143 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 144 goto err; 145 } 146 if (!ASN1_STRING_set(a->parameter->value.sequence, p, i)) { 147 OPENSSL_free(p); 148 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 149 goto err; 150 } 151 OPENSSL_free(p); 152 } 153#endif 154#ifndef OPENSSL_NO_EC 155 else if (pkey->type == EVP_PKEY_EC) { 156 int nid = 0; 157 unsigned char *pp; 158 EC_KEY *ec_key; 159 const EC_GROUP *group; 160 161 ec_key = pkey->pkey.ec; 162 ASN1_TYPE_free(a->parameter); 163 164 if ((a->parameter = ASN1_TYPE_new()) == NULL) { 165 X509err(X509_F_X509_PUBKEY_SET, ERR_R_ASN1_LIB); 166 goto err; 167 } 168 169 group = EC_KEY_get0_group(ec_key); 170 if (EC_GROUP_get_asn1_flag(group) 171 && (nid = EC_GROUP_get_curve_name(group))) { 172 /* just set the OID */ 173 a->parameter->type = V_ASN1_OBJECT; 174 a->parameter->value.object = OBJ_nid2obj(nid); 175 } else { /* explicit parameters */ 176 177 if ((i = i2d_ECParameters(ec_key, NULL)) == 0) { 178 X509err(X509_F_X509_PUBKEY_SET, ERR_R_EC_LIB); 179 goto err; 180 } 181 if ((p = (unsigned char *)OPENSSL_malloc(i)) == NULL) { 182 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 183 goto err; 184 } 185 pp = p; 186 if (!i2d_ECParameters(ec_key, &pp)) { 187 X509err(X509_F_X509_PUBKEY_SET, ERR_R_EC_LIB); 188 OPENSSL_free(p); 189 goto err; 190 } 191 a->parameter->type = V_ASN1_SEQUENCE; 192 if ((a->parameter->value.sequence = ASN1_STRING_new()) == NULL) { 193 X509err(X509_F_X509_PUBKEY_SET, ERR_R_ASN1_LIB); 194 OPENSSL_free(p); 195 goto err; 196 } 197 ASN1_STRING_set(a->parameter->value.sequence, p, i); 198 OPENSSL_free(p); 199 } 200 } 201#endif 202 else if (1) { 203 X509err(X509_F_X509_PUBKEY_SET, X509_R_UNSUPPORTED_ALGORITHM); 204 goto err; 205 } 206 207 if ((i = i2d_PublicKey(pkey, NULL)) <= 0) 208 goto err; 209 if ((s = (unsigned char *)OPENSSL_malloc(i + 1)) == NULL) { 210 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 211 goto err; 212 } 213 p = s; 214 i2d_PublicKey(pkey, &p); 215 if (!M_ASN1_BIT_STRING_set(pk->public_key, s, i)) { 216 X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); 217 goto err; 218 } 219 /* Set number of unused bits to zero */ 220 pk->public_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); 221 pk->public_key->flags |= ASN1_STRING_FLAG_BITS_LEFT; 222 223 OPENSSL_free(s); 224 225#if 0 226 CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); 227 pk->pkey = pkey; 228#endif 229 230 if (*x != NULL) 231 X509_PUBKEY_free(*x); 232 233 *x = pk; 234 235 return 1; 236 err: 237 if (pk != NULL) 238 X509_PUBKEY_free(pk); 239 return 0; 240} 241 242EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) 243{ 244 EVP_PKEY *ret = NULL; 245 long j; 246 int type; 247 const unsigned char *p; 248#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) 249 const unsigned char *cp; 250 X509_ALGOR *a; 251#endif 252 253 if (key == NULL) 254 goto err; 255 256 if (key->pkey != NULL) { 257 CRYPTO_add(&key->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); 258 return (key->pkey); 259 } 260 261 if (key->public_key == NULL) 262 goto err; 263 264 type = OBJ_obj2nid(key->algor->algorithm); 265 if ((ret = EVP_PKEY_new()) == NULL) { 266 X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE); 267 goto err; 268 } 269 ret->type = EVP_PKEY_type(type); 270 271 /* the parameters must be extracted before the public key (ECDSA!) */ 272 273#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) 274 a = key->algor; 275#endif 276 277 if (0) ; 278#ifndef OPENSSL_NO_DSA 279 else if (ret->type == EVP_PKEY_DSA) { 280 if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) { 281 if ((ret->pkey.dsa = DSA_new()) == NULL) { 282 X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE); 283 goto err; 284 } 285 ret->pkey.dsa->write_params = 0; 286 cp = p = a->parameter->value.sequence->data; 287 j = a->parameter->value.sequence->length; 288 if (!d2i_DSAparams(&ret->pkey.dsa, &cp, (long)j)) 289 goto err; 290 } 291 ret->save_parameters = 1; 292 } 293#endif 294#ifndef OPENSSL_NO_EC 295 else if (ret->type == EVP_PKEY_EC) { 296 if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) { 297 /* 298 * type == V_ASN1_SEQUENCE => we have explicit parameters (e.g. 299 * parameters in the X9_62_EC_PARAMETERS-structure ) 300 */ 301 if ((ret->pkey.ec = EC_KEY_new()) == NULL) { 302 X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE); 303 goto err; 304 } 305 cp = p = a->parameter->value.sequence->data; 306 j = a->parameter->value.sequence->length; 307 if (!d2i_ECParameters(&ret->pkey.ec, &cp, (long)j)) { 308 X509err(X509_F_X509_PUBKEY_GET, ERR_R_EC_LIB); 309 goto err; 310 } 311 } else if (a->parameter && (a->parameter->type == V_ASN1_OBJECT)) { 312 /* 313 * type == V_ASN1_OBJECT => the parameters are given by an asn1 314 * OID 315 */ 316 EC_KEY *ec_key; 317 EC_GROUP *group; 318 319 if (ret->pkey.ec == NULL) 320 ret->pkey.ec = EC_KEY_new(); 321 ec_key = ret->pkey.ec; 322 if (ec_key == NULL) 323 goto err; 324 group = 325 EC_GROUP_new_by_curve_name(OBJ_obj2nid 326 (a->parameter->value.object)); 327 if (group == NULL) 328 goto err; 329 EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); 330 if (EC_KEY_set_group(ec_key, group) == 0) 331 goto err; 332 EC_GROUP_free(group); 333 } 334 /* 335 * the case implicitlyCA is currently not implemented 336 */ 337 ret->save_parameters = 1; 338 } 339#endif 340 341 p = key->public_key->data; 342 j = key->public_key->length; 343 if (!d2i_PublicKey(type, &ret, &p, (long)j)) { 344 X509err(X509_F_X509_PUBKEY_GET, X509_R_ERR_ASN1_LIB); 345 goto err; 346 } 347 348 /* Check to see if another thread set key->pkey first */ 349 CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY); 350 if (key->pkey) { 351 CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY); 352 EVP_PKEY_free(ret); 353 ret = key->pkey; 354 } else { 355 key->pkey = ret; 356 CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY); 357 } 358 CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_EVP_PKEY); 359 return (ret); 360 err: 361 if (ret != NULL) 362 EVP_PKEY_free(ret); 363 return (NULL); 364} 365 366/* 367 * Now two pseudo ASN1 routines that take an EVP_PKEY structure and encode or 368 * decode as X509_PUBKEY 369 */ 370 371EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length) 372{ 373 X509_PUBKEY *xpk; 374 EVP_PKEY *pktmp; 375 xpk = d2i_X509_PUBKEY(NULL, pp, length); 376 if (!xpk) 377 return NULL; 378 pktmp = X509_PUBKEY_get(xpk); 379 X509_PUBKEY_free(xpk); 380 if (!pktmp) 381 return NULL; 382 if (a) { 383 EVP_PKEY_free(*a); 384 *a = pktmp; 385 } 386 return pktmp; 387} 388 389int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp) 390{ 391 X509_PUBKEY *xpk = NULL; 392 int ret; 393 if (!a) 394 return 0; 395 if (!X509_PUBKEY_set(&xpk, a)) 396 return 0; 397 ret = i2d_X509_PUBKEY(xpk, pp); 398 X509_PUBKEY_free(xpk); 399 return ret; 400} 401 402/* 403 * The following are equivalents but which return RSA and DSA keys 404 */ 405#ifndef OPENSSL_NO_RSA 406RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, long length) 407{ 408 EVP_PKEY *pkey; 409 RSA *key; 410 const unsigned char *q; 411 q = *pp; 412 pkey = d2i_PUBKEY(NULL, &q, length); 413 if (!pkey) 414 return NULL; 415 key = EVP_PKEY_get1_RSA(pkey); 416 EVP_PKEY_free(pkey); 417 if (!key) 418 return NULL; 419 *pp = q; 420 if (a) { 421 RSA_free(*a); 422 *a = key; 423 } 424 return key; 425} 426 427int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp) 428{ 429 EVP_PKEY *pktmp; 430 int ret; 431 if (!a) 432 return 0; 433 pktmp = EVP_PKEY_new(); 434 if (!pktmp) { 435 ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE); 436 return 0; 437 } 438 EVP_PKEY_set1_RSA(pktmp, a); 439 ret = i2d_PUBKEY(pktmp, pp); 440 EVP_PKEY_free(pktmp); 441 return ret; 442} 443#endif 444 445#ifndef OPENSSL_NO_DSA 446DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, long length) 447{ 448 EVP_PKEY *pkey; 449 DSA *key; 450 const unsigned char *q; 451 q = *pp; 452 pkey = d2i_PUBKEY(NULL, &q, length); 453 if (!pkey) 454 return NULL; 455 key = EVP_PKEY_get1_DSA(pkey); 456 EVP_PKEY_free(pkey); 457 if (!key) 458 return NULL; 459 *pp = q; 460 if (a) { 461 DSA_free(*a); 462 *a = key; 463 } 464 return key; 465} 466 467int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp) 468{ 469 EVP_PKEY *pktmp; 470 int ret; 471 if (!a) 472 return 0; 473 pktmp = EVP_PKEY_new(); 474 if (!pktmp) { 475 ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE); 476 return 0; 477 } 478 EVP_PKEY_set1_DSA(pktmp, a); 479 ret = i2d_PUBKEY(pktmp, pp); 480 EVP_PKEY_free(pktmp); 481 return ret; 482} 483#endif 484 485#ifndef OPENSSL_NO_EC 486EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) 487{ 488 EVP_PKEY *pkey; 489 EC_KEY *key; 490 const unsigned char *q; 491 q = *pp; 492 pkey = d2i_PUBKEY(NULL, &q, length); 493 if (!pkey) 494 return (NULL); 495 key = EVP_PKEY_get1_EC_KEY(pkey); 496 EVP_PKEY_free(pkey); 497 if (!key) 498 return (NULL); 499 *pp = q; 500 if (a) { 501 EC_KEY_free(*a); 502 *a = key; 503 } 504 return (key); 505} 506 507int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp) 508{ 509 EVP_PKEY *pktmp; 510 int ret; 511 if (!a) 512 return (0); 513 if ((pktmp = EVP_PKEY_new()) == NULL) { 514 ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE); 515 return (0); 516 } 517 EVP_PKEY_set1_EC_KEY(pktmp, a); 518 ret = i2d_PUBKEY(pktmp, pp); 519 EVP_PKEY_free(pktmp); 520 return (ret); 521} 522#endif 523