sl@0: /* crypto/asn1/x_pubkey.c */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: sl@0: #include sl@0: #include "cryptlib.h" sl@0: #include sl@0: #include sl@0: #ifndef OPENSSL_NO_RSA sl@0: #include sl@0: #endif sl@0: #ifndef OPENSSL_NO_DSA sl@0: #include sl@0: #endif sl@0: sl@0: /* Minor tweak to operation: free up EVP_PKEY */ sl@0: static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it) sl@0: { sl@0: if (operation == ASN1_OP_FREE_POST) sl@0: { sl@0: X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; sl@0: EVP_PKEY_free(pubkey->pkey); sl@0: } sl@0: return 1; sl@0: } sl@0: sl@0: ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { sl@0: ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), sl@0: ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) sl@0: } ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) sl@0: sl@0: IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) sl@0: sl@0: EXPORT_C int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) sl@0: { sl@0: X509_PUBKEY *pk=NULL; sl@0: X509_ALGOR *a; sl@0: ASN1_OBJECT *o; sl@0: unsigned char *s,*p = NULL; sl@0: int i; sl@0: sl@0: if (x == NULL) return(0); sl@0: sl@0: if ((pk=X509_PUBKEY_new()) == NULL) goto err; sl@0: a=pk->algor; sl@0: sl@0: /* set the algorithm id */ sl@0: if ((o=OBJ_nid2obj(pkey->type)) == NULL) goto err; sl@0: ASN1_OBJECT_free(a->algorithm); sl@0: a->algorithm=o; sl@0: sl@0: /* Set the parameter list */ sl@0: if (!pkey->save_parameters || (pkey->type == EVP_PKEY_RSA)) sl@0: { sl@0: if ((a->parameter == NULL) || sl@0: (a->parameter->type != V_ASN1_NULL)) sl@0: { sl@0: ASN1_TYPE_free(a->parameter); sl@0: if (!(a->parameter=ASN1_TYPE_new())) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: a->parameter->type=V_ASN1_NULL; sl@0: } sl@0: } sl@0: #ifndef OPENSSL_NO_DSA sl@0: else if (pkey->type == EVP_PKEY_DSA) sl@0: { sl@0: unsigned char *pp; sl@0: DSA *dsa; sl@0: sl@0: dsa=pkey->pkey.dsa; sl@0: dsa->write_params=0; sl@0: ASN1_TYPE_free(a->parameter); sl@0: if ((i=i2d_DSAparams(dsa,NULL)) <= 0) sl@0: goto err; sl@0: if (!(p=(unsigned char *)OPENSSL_malloc(i))) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: pp=p; sl@0: i2d_DSAparams(dsa,&pp); sl@0: if (!(a->parameter=ASN1_TYPE_new())) sl@0: { sl@0: OPENSSL_free(p); sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: a->parameter->type=V_ASN1_SEQUENCE; sl@0: if (!(a->parameter->value.sequence=ASN1_STRING_new())) sl@0: { sl@0: OPENSSL_free(p); sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: if (!ASN1_STRING_set(a->parameter->value.sequence,p,i)) sl@0: { sl@0: OPENSSL_free(p); sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: OPENSSL_free(p); sl@0: } sl@0: #endif sl@0: #ifndef OPENSSL_NO_EC sl@0: else if (pkey->type == EVP_PKEY_EC) sl@0: { sl@0: int nid=0; sl@0: unsigned char *pp; sl@0: EC_KEY *ec_key; sl@0: const EC_GROUP *group; sl@0: sl@0: ec_key = pkey->pkey.ec; sl@0: ASN1_TYPE_free(a->parameter); sl@0: sl@0: if ((a->parameter = ASN1_TYPE_new()) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET, ERR_R_ASN1_LIB); sl@0: goto err; sl@0: } sl@0: sl@0: group = EC_KEY_get0_group(ec_key); sl@0: if (EC_GROUP_get_asn1_flag(group) sl@0: && (nid = EC_GROUP_get_curve_name(group))) sl@0: { sl@0: /* just set the OID */ sl@0: a->parameter->type = V_ASN1_OBJECT; sl@0: a->parameter->value.object = OBJ_nid2obj(nid); sl@0: } sl@0: else /* explicit parameters */ sl@0: { sl@0: if ((i = i2d_ECParameters(ec_key, NULL)) == 0) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET, ERR_R_EC_LIB); sl@0: goto err; sl@0: } sl@0: if ((p = (unsigned char *) OPENSSL_malloc(i)) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: pp = p; sl@0: if (!i2d_ECParameters(ec_key, &pp)) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET, ERR_R_EC_LIB); sl@0: OPENSSL_free(p); sl@0: goto err; sl@0: } sl@0: a->parameter->type = V_ASN1_SEQUENCE; sl@0: if ((a->parameter->value.sequence = ASN1_STRING_new()) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET, ERR_R_ASN1_LIB); sl@0: OPENSSL_free(p); sl@0: goto err; sl@0: } sl@0: ASN1_STRING_set(a->parameter->value.sequence, p, i); sl@0: OPENSSL_free(p); sl@0: } sl@0: } sl@0: #endif sl@0: else if (1) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET,X509_R_UNSUPPORTED_ALGORITHM); sl@0: goto err; sl@0: } sl@0: sl@0: if ((i=i2d_PublicKey(pkey,NULL)) <= 0) goto err; sl@0: if ((s=(unsigned char *)OPENSSL_malloc(i+1)) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: p=s; sl@0: i2d_PublicKey(pkey,&p); sl@0: if (!M_ASN1_BIT_STRING_set(pk->public_key,s,i)) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: /* Set number of unused bits to zero */ sl@0: pk->public_key->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); sl@0: pk->public_key->flags|=ASN1_STRING_FLAG_BITS_LEFT; sl@0: sl@0: OPENSSL_free(s); sl@0: sl@0: #if 0 sl@0: CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY); sl@0: pk->pkey=pkey; sl@0: #endif sl@0: sl@0: if (*x != NULL) sl@0: X509_PUBKEY_free(*x); sl@0: sl@0: *x=pk; sl@0: sl@0: return 1; sl@0: err: sl@0: if (pk != NULL) X509_PUBKEY_free(pk); sl@0: return 0; sl@0: } sl@0: sl@0: EXPORT_C EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) sl@0: { sl@0: EVP_PKEY *ret=NULL; sl@0: long j; sl@0: int type; sl@0: const unsigned char *p; sl@0: #if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) sl@0: const unsigned char *cp; sl@0: X509_ALGOR *a; sl@0: #endif sl@0: sl@0: if (key == NULL) goto err; sl@0: sl@0: if (key->pkey != NULL) sl@0: { sl@0: CRYPTO_add(&key->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); sl@0: return(key->pkey); sl@0: } sl@0: sl@0: if (key->public_key == NULL) goto err; sl@0: sl@0: type=OBJ_obj2nid(key->algor->algorithm); sl@0: if ((ret = EVP_PKEY_new()) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: ret->type = EVP_PKEY_type(type); sl@0: sl@0: /* the parameters must be extracted before the public key (ECDSA!) */ sl@0: sl@0: #if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) sl@0: a=key->algor; sl@0: #endif sl@0: sl@0: if (0) sl@0: ; sl@0: #ifndef OPENSSL_NO_DSA sl@0: else if (ret->type == EVP_PKEY_DSA) sl@0: { sl@0: if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) sl@0: { sl@0: if ((ret->pkey.dsa = DSA_new()) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: ret->pkey.dsa->write_params=0; sl@0: cp=p=a->parameter->value.sequence->data; sl@0: j=a->parameter->value.sequence->length; sl@0: if (!d2i_DSAparams(&ret->pkey.dsa, &cp, (long)j)) sl@0: goto err; sl@0: } sl@0: ret->save_parameters=1; sl@0: } sl@0: #endif sl@0: #ifndef OPENSSL_NO_EC sl@0: else if (ret->type == EVP_PKEY_EC) sl@0: { sl@0: if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE)) sl@0: { sl@0: /* type == V_ASN1_SEQUENCE => we have explicit parameters sl@0: * (e.g. parameters in the X9_62_EC_PARAMETERS-structure ) sl@0: */ sl@0: if ((ret->pkey.ec= EC_KEY_new()) == NULL) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_GET, sl@0: ERR_R_MALLOC_FAILURE); sl@0: goto err; sl@0: } sl@0: cp = p = a->parameter->value.sequence->data; sl@0: j = a->parameter->value.sequence->length; sl@0: if (!d2i_ECParameters(&ret->pkey.ec, &cp, (long)j)) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_GET, ERR_R_EC_LIB); sl@0: goto err; sl@0: } sl@0: } sl@0: else if (a->parameter && (a->parameter->type == V_ASN1_OBJECT)) sl@0: { sl@0: /* type == V_ASN1_OBJECT => the parameters are given sl@0: * by an asn1 OID sl@0: */ sl@0: EC_KEY *ec_key; sl@0: EC_GROUP *group; sl@0: sl@0: if (ret->pkey.ec == NULL) sl@0: ret->pkey.ec = EC_KEY_new(); sl@0: ec_key = ret->pkey.ec; sl@0: if (ec_key == NULL) sl@0: goto err; sl@0: group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(a->parameter->value.object)); sl@0: if (group == NULL) sl@0: goto err; sl@0: EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); sl@0: if (EC_KEY_set_group(ec_key, group) == 0) sl@0: goto err; sl@0: EC_GROUP_free(group); sl@0: } sl@0: /* the case implicitlyCA is currently not implemented */ sl@0: ret->save_parameters = 1; sl@0: } sl@0: #endif sl@0: sl@0: p=key->public_key->data; sl@0: j=key->public_key->length; sl@0: if (!d2i_PublicKey(type, &ret, &p, (long)j)) sl@0: { sl@0: X509err(X509_F_X509_PUBKEY_GET, X509_R_ERR_ASN1_LIB); sl@0: goto err; sl@0: } sl@0: sl@0: key->pkey = ret; sl@0: CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_EVP_PKEY); sl@0: return(ret); sl@0: err: sl@0: if (ret != NULL) sl@0: EVP_PKEY_free(ret); sl@0: return(NULL); sl@0: } sl@0: sl@0: /* Now two pseudo ASN1 routines that take an EVP_PKEY structure sl@0: * and encode or decode as X509_PUBKEY sl@0: */ sl@0: sl@0: EXPORT_C EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, sl@0: long length) sl@0: { sl@0: X509_PUBKEY *xpk; sl@0: EVP_PKEY *pktmp; sl@0: xpk = d2i_X509_PUBKEY(NULL, pp, length); sl@0: if(!xpk) return NULL; sl@0: pktmp = X509_PUBKEY_get(xpk); sl@0: X509_PUBKEY_free(xpk); sl@0: if(!pktmp) return NULL; sl@0: if(a) sl@0: { sl@0: EVP_PKEY_free(*a); sl@0: *a = pktmp; sl@0: } sl@0: return pktmp; sl@0: } sl@0: sl@0: EXPORT_C int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp) sl@0: { sl@0: X509_PUBKEY *xpk=NULL; sl@0: int ret; sl@0: if(!a) return 0; sl@0: if(!X509_PUBKEY_set(&xpk, a)) return 0; sl@0: ret = i2d_X509_PUBKEY(xpk, pp); sl@0: X509_PUBKEY_free(xpk); sl@0: return ret; sl@0: } sl@0: sl@0: /* The following are equivalents but which return RSA and DSA sl@0: * keys sl@0: */ sl@0: #ifndef OPENSSL_NO_RSA sl@0: EXPORT_C RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, sl@0: long length) sl@0: { sl@0: EVP_PKEY *pkey; sl@0: RSA *key; sl@0: const unsigned char *q; sl@0: q = *pp; sl@0: pkey = d2i_PUBKEY(NULL, &q, length); sl@0: if (!pkey) return NULL; sl@0: key = EVP_PKEY_get1_RSA(pkey); sl@0: EVP_PKEY_free(pkey); sl@0: if (!key) return NULL; sl@0: *pp = q; sl@0: if (a) sl@0: { sl@0: RSA_free(*a); sl@0: *a = key; sl@0: } sl@0: return key; sl@0: } sl@0: sl@0: EXPORT_C int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp) sl@0: { sl@0: EVP_PKEY *pktmp; sl@0: int ret; sl@0: if (!a) return 0; sl@0: pktmp = EVP_PKEY_new(); sl@0: if (!pktmp) sl@0: { sl@0: ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE); sl@0: return 0; sl@0: } sl@0: EVP_PKEY_set1_RSA(pktmp, a); sl@0: ret = i2d_PUBKEY(pktmp, pp); sl@0: EVP_PKEY_free(pktmp); sl@0: return ret; sl@0: } sl@0: #endif sl@0: sl@0: #ifndef OPENSSL_NO_DSA sl@0: EXPORT_C DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, sl@0: long length) sl@0: { sl@0: EVP_PKEY *pkey; sl@0: DSA *key; sl@0: const unsigned char *q; sl@0: q = *pp; sl@0: pkey = d2i_PUBKEY(NULL, &q, length); sl@0: if (!pkey) return NULL; sl@0: key = EVP_PKEY_get1_DSA(pkey); sl@0: EVP_PKEY_free(pkey); sl@0: if (!key) return NULL; sl@0: *pp = q; sl@0: if (a) sl@0: { sl@0: DSA_free(*a); sl@0: *a = key; sl@0: } sl@0: return key; sl@0: } sl@0: sl@0: EXPORT_C int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp) sl@0: { sl@0: EVP_PKEY *pktmp; sl@0: int ret; sl@0: if(!a) return 0; sl@0: pktmp = EVP_PKEY_new(); sl@0: if(!pktmp) sl@0: { sl@0: ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE); sl@0: return 0; sl@0: } sl@0: EVP_PKEY_set1_DSA(pktmp, a); sl@0: ret = i2d_PUBKEY(pktmp, pp); sl@0: EVP_PKEY_free(pktmp); sl@0: return ret; sl@0: } sl@0: #endif sl@0: sl@0: #ifndef OPENSSL_NO_EC sl@0: EXPORT_C EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) sl@0: { sl@0: EVP_PKEY *pkey; sl@0: EC_KEY *key; sl@0: const unsigned char *q; sl@0: q = *pp; sl@0: pkey = d2i_PUBKEY(NULL, &q, length); sl@0: if (!pkey) return(NULL); sl@0: key = EVP_PKEY_get1_EC_KEY(pkey); sl@0: EVP_PKEY_free(pkey); sl@0: if (!key) return(NULL); sl@0: *pp = q; sl@0: if (a) sl@0: { sl@0: EC_KEY_free(*a); sl@0: *a = key; sl@0: } sl@0: return(key); sl@0: } sl@0: sl@0: EXPORT_C int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp) sl@0: { sl@0: EVP_PKEY *pktmp; sl@0: int ret; sl@0: if (!a) return(0); sl@0: if ((pktmp = EVP_PKEY_new()) == NULL) sl@0: { sl@0: ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE); sl@0: return(0); sl@0: } sl@0: EVP_PKEY_set1_EC_KEY(pktmp, a); sl@0: ret = i2d_PUBKEY(pktmp, pp); sl@0: EVP_PKEY_free(pktmp); sl@0: return(ret); sl@0: } sl@0: #endif