1232633Smp/* crypto/asn1/d2i_pr.c */
259243Sobrien/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
359243Sobrien * All rights reserved.
459243Sobrien *
559243Sobrien * This package is an SSL implementation written
659243Sobrien * by Eric Young (eay@cryptsoft.com).
759243Sobrien * The implementation was written so as to conform with Netscapes SSL.
859243Sobrien *
959243Sobrien * This library is free for commercial and non-commercial use as long as
1059243Sobrien * the following conditions are aheared to.  The following conditions
1159243Sobrien * apply to all code found in this distribution, be it the RC4, RSA,
1259243Sobrien * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1359243Sobrien * included with this distribution is covered by the same copyright terms
1459243Sobrien * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1559243Sobrien *
1659243Sobrien * Copyright remains Eric Young's, and as such any Copyright notices in
17100616Smp * the code are not to be removed.
1859243Sobrien * If this package is used in a product, Eric Young should be given attribution
1959243Sobrien * as the author of the parts of the library used.
2059243Sobrien * This can be in the form of a textual message at program startup or
2159243Sobrien * in documentation (online or textual) provided with the package.
2259243Sobrien *
2359243Sobrien * Redistribution and use in source and binary forms, with or without
2459243Sobrien * modification, are permitted provided that the following conditions
2559243Sobrien * are met:
2659243Sobrien * 1. Redistributions of source code must retain the copyright
2759243Sobrien *    notice, this list of conditions and the following disclaimer.
2859243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
2959243Sobrien *    notice, this list of conditions and the following disclaimer in the
3059243Sobrien *    documentation and/or other materials provided with the distribution.
3159243Sobrien * 3. All advertising materials mentioning features or use of this software
3259243Sobrien *    must display the following acknowledgement:
3359243Sobrien *    "This product includes cryptographic software written by
3459243Sobrien *     Eric Young (eay@cryptsoft.com)"
35232633Smp *    The word 'cryptographic' can be left out if the rouines from the library
3659243Sobrien *    being used are not cryptographic related :-).
3759243Sobrien * 4. If you include any Windows specific code (or a derivative thereof) from
38100616Smp *    the apps directory (application code) you must include an acknowledgement:
3959243Sobrien *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4059243Sobrien *
4159243Sobrien * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5159243Sobrien * SUCH DAMAGE.
5259243Sobrien *
5359243Sobrien * The licence and distribution terms for any publically available version or
5459243Sobrien * derivative of this code cannot be changed.  i.e. this code cannot simply be
5559243Sobrien * copied and put under another distribution licence
5659243Sobrien * [including the GNU Public Licence.]
5759243Sobrien */
5859243Sobrien
5959243Sobrien#include <stdio.h>
6059243Sobrien#include "cryptlib.h"
6159243Sobrien#include <openssl/bn.h>
6259243Sobrien#include <openssl/evp.h>
6359243Sobrien#include <openssl/objects.h>
6459243Sobrien#ifndef OPENSSL_NO_ENGINE
6559243Sobrien#include <openssl/engine.h>
6659243Sobrien#endif
67167465Smp#include <openssl/x509.h>
68167465Smp#include <openssl/asn1.h>
69167465Smp#include "asn1_locl.h"
70167465Smp
71167465SmpEVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp,
72167465Smp	     long length)
73167465Smp	{
74167465Smp	EVP_PKEY *ret;
75167465Smp
7659243Sobrien	if ((a == NULL) || (*a == NULL))
77167465Smp		{
7859243Sobrien		if ((ret=EVP_PKEY_new()) == NULL)
79167465Smp			{
8059243Sobrien			ASN1err(ASN1_F_D2I_PRIVATEKEY,ERR_R_EVP_LIB);
8159243Sobrien			return(NULL);
82167465Smp			}
8359243Sobrien		}
84167465Smp	else
85167465Smp		{
86167465Smp		ret= *a;
87167465Smp#ifndef OPENSSL_NO_ENGINE
88167465Smp		if (ret->engine)
89167465Smp			{
90167465Smp			ENGINE_finish(ret->engine);
91167465Smp			ret->engine = NULL;
92167465Smp			}
93167465Smp#endif
9459243Sobrien		}
9559243Sobrien
9659243Sobrien	if (!EVP_PKEY_set_type(ret, type))
97167465Smp		{
98167465Smp		ASN1err(ASN1_F_D2I_PRIVATEKEY,ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE);
99167465Smp		goto err;
100167465Smp		}
101167465Smp
102167465Smp	if (!ret->ameth->old_priv_decode ||
103167465Smp			!ret->ameth->old_priv_decode(ret, pp, length))
104167465Smp		{
10559243Sobrien		if (ret->ameth->priv_decode)
10659243Sobrien			{
107167465Smp			PKCS8_PRIV_KEY_INFO *p8=NULL;
10859243Sobrien			p8=d2i_PKCS8_PRIV_KEY_INFO(NULL,pp,length);
109167465Smp			if (!p8) goto err;
11059243Sobrien			EVP_PKEY_free(ret);
11159243Sobrien			ret = EVP_PKCS82PKEY(p8);
112167465Smp			PKCS8_PRIV_KEY_INFO_free(p8);
113167465Smp
11459243Sobrien			}
11559243Sobrien		else
11659243Sobrien			{
11759243Sobrien			ASN1err(ASN1_F_D2I_PRIVATEKEY,ERR_R_ASN1_LIB);
11859243Sobrien			goto err;
11959243Sobrien			}
12059243Sobrien		}
121167465Smp	if (a != NULL) (*a)=ret;
122167465Smp	return(ret);
123167465Smperr:
124167465Smp	if ((ret != NULL) && ((a == NULL) || (*a != ret))) EVP_PKEY_free(ret);
125167465Smp	return(NULL);
12659243Sobrien	}
12759243Sobrien
12859243Sobrien/* This works like d2i_PrivateKey() except it automatically works out the type */
12959243Sobrien
13059243SobrienEVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp,
13159243Sobrien	     long length)
13259243Sobrien{
13359243Sobrien	STACK_OF(ASN1_TYPE) *inkey;
13459243Sobrien	const unsigned char *p;
13559243Sobrien	int keytype;
13659243Sobrien	p = *pp;
13759243Sobrien	/* Dirty trick: read in the ASN1 data into a STACK_OF(ASN1_TYPE):
13859243Sobrien	 * by analyzing it we can determine the passed structure: this
13959243Sobrien	 * assumes the input is surrounded by an ASN1 SEQUENCE.
14059243Sobrien	 */
14159243Sobrien	inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, length);
142167465Smp	/* Since we only need to discern "traditional format" RSA and DSA
143167465Smp	 * keys we can just count the elements.
14459243Sobrien         */
145167465Smp	if(sk_ASN1_TYPE_num(inkey) == 6)
14659243Sobrien		keytype = EVP_PKEY_DSA;
14759243Sobrien	else if (sk_ASN1_TYPE_num(inkey) == 4)
14859243Sobrien		keytype = EVP_PKEY_EC;
149167465Smp	else if (sk_ASN1_TYPE_num(inkey) == 3)
15059243Sobrien		{ /* This seems to be PKCS8, not traditional format */
151167465Smp			PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL,pp,length);
152167465Smp			EVP_PKEY *ret;
153167465Smp
154167465Smp			sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
155167465Smp			if (!p8)
15659243Sobrien				{
15759243Sobrien				ASN1err(ASN1_F_D2I_AUTOPRIVATEKEY,ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
158167465Smp				return NULL;
159167465Smp				}
160167465Smp			ret = EVP_PKCS82PKEY(p8);
16159243Sobrien			PKCS8_PRIV_KEY_INFO_free(p8);
16259243Sobrien			if (a) {
16359243Sobrien				*a = ret;
16459243Sobrien			}
16559243Sobrien			return ret;
16659243Sobrien		}
16759243Sobrien	else keytype = EVP_PKEY_RSA;
168167465Smp	sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
16959243Sobrien	return d2i_PrivateKey(keytype, a, pp, length);
17059243Sobrien}
17159243Sobrien