1/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to.  The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 *    must display the following acknowledgement:
32 *    "This product includes cryptographic software written by
33 *     Eric Young (eay@cryptsoft.com)"
34 *    The word 'cryptographic' can be left out if the rouines from the library
35 *    being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 *    the apps directory (application code) you must include an acknowledgement:
38 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed.  i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.] */
56
57#include <openssl/asn1.h>
58#include <openssl/asn1t.h>
59#include <openssl/err.h>
60#include <openssl/evp.h>
61#include <openssl/mem.h>
62#include <openssl/obj.h>
63#include <openssl/x509.h>
64
65#include "../evp/internal.h"
66
67
68/* Minor tweak to operation: free up EVP_PKEY */
69static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
70			void *exarg)
71	{
72	if (operation == ASN1_OP_FREE_POST)
73		{
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
91	if (x == NULL) return(0);
92
93	if ((pk=X509_PUBKEY_new()) == NULL) goto error;
94
95	if (pkey->ameth)
96		{
97		if (pkey->ameth->pub_encode)
98			{
99			if (!pkey->ameth->pub_encode(pk, pkey))
100				{
101				OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_PUBLIC_KEY_ENCODE_ERROR);
102				goto error;
103				}
104			}
105		else
106			{
107			OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_METHOD_NOT_SUPPORTED);
108			goto error;
109			}
110		}
111	else
112		{
113		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_set, X509_R_UNSUPPORTED_ALGORITHM);
114		goto error;
115		}
116
117	if (*x != NULL)
118		X509_PUBKEY_free(*x);
119
120	*x=pk;
121
122	return 1;
123error:
124	if (pk != NULL) X509_PUBKEY_free(pk);
125	return 0;
126	}
127
128EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
129	{
130	EVP_PKEY *ret=NULL;
131
132	if (key == NULL) goto error;
133
134	if (key->pkey != NULL)
135		{
136		return EVP_PKEY_dup(key->pkey);
137		}
138
139	if (key->public_key == NULL) goto error;
140
141	if ((ret = EVP_PKEY_new()) == NULL)
142		{
143		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, ERR_R_MALLOC_FAILURE);
144		goto error;
145		}
146
147	if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm)))
148		{
149		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_UNSUPPORTED_ALGORITHM);
150		goto error;
151		}
152
153	if (ret->ameth->pub_decode)
154		{
155		if (!ret->ameth->pub_decode(ret, key))
156			{
157			OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_PUBLIC_KEY_DECODE_ERROR);
158			goto error;
159			}
160		}
161	else
162		{
163		OPENSSL_PUT_ERROR(X509, X509_PUBKEY_get, X509_R_METHOD_NOT_SUPPORTED);
164		goto error;
165		}
166
167	/* Check to see if another thread set key->pkey first */
168	CRYPTO_w_lock(CRYPTO_LOCK_EVP_PKEY);
169	if (key->pkey)
170		{
171		CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
172		EVP_PKEY_free(ret);
173		ret = key->pkey;
174		}
175	else
176		{
177		key->pkey = ret;
178		CRYPTO_w_unlock(CRYPTO_LOCK_EVP_PKEY);
179		}
180
181	return EVP_PKEY_dup(ret);
182
183	error:
184	if (ret != NULL)
185		EVP_PKEY_free(ret);
186	return(NULL);
187	}
188
189/* Now two pseudo ASN1 routines that take an EVP_PKEY structure
190 * and encode or decode as X509_PUBKEY
191 */
192
193EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp,
194	     long length)
195	{
196	X509_PUBKEY *xpk;
197	EVP_PKEY *pktmp;
198	xpk = d2i_X509_PUBKEY(NULL, pp, length);
199	if(!xpk) return NULL;
200	pktmp = X509_PUBKEY_get(xpk);
201	X509_PUBKEY_free(xpk);
202	if(!pktmp) return NULL;
203	if(a)
204		{
205		EVP_PKEY_free(*a);
206		*a = pktmp;
207		}
208	return pktmp;
209	}
210
211int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp)
212	{
213	X509_PUBKEY *xpk=NULL;
214	int ret;
215	if(!a) return 0;
216	if(!X509_PUBKEY_set(&xpk, (EVP_PKEY*) a)) return 0;
217	ret = i2d_X509_PUBKEY(xpk, pp);
218	X509_PUBKEY_free(xpk);
219	return ret;
220	}
221
222/* The following are equivalents but which return RSA and DSA
223 * keys
224 */
225RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp,
226	     long length)
227	{
228	EVP_PKEY *pkey;
229	RSA *key;
230	const unsigned char *q;
231	q = *pp;
232	pkey = d2i_PUBKEY(NULL, &q, length);
233	if (!pkey) return NULL;
234	key = EVP_PKEY_get1_RSA(pkey);
235	EVP_PKEY_free(pkey);
236	if (!key) return NULL;
237	*pp = q;
238	if (a)
239		{
240		RSA_free(*a);
241		*a = key;
242		}
243	return key;
244	}
245
246int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp)
247	{
248	EVP_PKEY *pktmp;
249	int ret;
250	if (!a) return 0;
251	pktmp = EVP_PKEY_new();
252	if (!pktmp)
253		{
254		OPENSSL_PUT_ERROR(X509, i2d_RSA_PUBKEY, ERR_R_MALLOC_FAILURE);
255		return 0;
256		}
257	EVP_PKEY_set1_RSA(pktmp, (RSA*) a);
258	ret = i2d_PUBKEY(pktmp, pp);
259	EVP_PKEY_free(pktmp);
260	return ret;
261	}
262
263#ifndef OPENSSL_NO_DSA
264DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp,
265	     long length)
266	{
267	EVP_PKEY *pkey;
268	DSA *key;
269	const unsigned char *q;
270	q = *pp;
271	pkey = d2i_PUBKEY(NULL, &q, length);
272	if (!pkey) return NULL;
273	key = EVP_PKEY_get1_DSA(pkey);
274	EVP_PKEY_free(pkey);
275	if (!key) return NULL;
276	*pp = q;
277	if (a)
278		{
279		DSA_free(*a);
280		*a = key;
281		}
282	return key;
283	}
284
285int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp)
286	{
287	EVP_PKEY *pktmp;
288	int ret;
289	if(!a) return 0;
290	pktmp = EVP_PKEY_new();
291	if(!pktmp)
292		{
293		OPENSSL_PUT_ERROR(X509, i2d_DSA_PUBKEY,  ERR_R_MALLOC_FAILURE);
294		return 0;
295		}
296	EVP_PKEY_set1_DSA(pktmp, (DSA*) a);
297	ret = i2d_PUBKEY(pktmp, pp);
298	EVP_PKEY_free(pktmp);
299	return ret;
300	}
301#endif
302
303EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
304	{
305	EVP_PKEY *pkey;
306	EC_KEY *key;
307	const unsigned char *q;
308	q = *pp;
309	pkey = d2i_PUBKEY(NULL, &q, length);
310	if (!pkey) return(NULL);
311	key = EVP_PKEY_get1_EC_KEY(pkey);
312	EVP_PKEY_free(pkey);
313	if (!key)  return(NULL);
314	*pp = q;
315	if (a)
316		{
317		EC_KEY_free(*a);
318		*a = key;
319		}
320	return(key);
321	}
322
323int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp)
324	{
325	EVP_PKEY *pktmp;
326	int ret;
327	if (!a)	return(0);
328	if ((pktmp = EVP_PKEY_new()) == NULL)
329		{
330		OPENSSL_PUT_ERROR(X509, i2d_EC_PUBKEY,  ERR_R_MALLOC_FAILURE);
331		return(0);
332		}
333	EVP_PKEY_set1_EC_KEY(pktmp, (EC_KEY*) a);
334	ret = i2d_PUBKEY(pktmp, pp);
335	EVP_PKEY_free(pktmp);
336	return(ret);
337	}
338
339int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj,
340					int ptype, void *pval,
341					unsigned char *penc, int penclen)
342	{
343	if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval))
344		return 0;
345	if (penc)
346		{
347		if (pub->public_key->data)
348			OPENSSL_free(pub->public_key->data);
349		pub->public_key->data = penc;
350		pub->public_key->length = penclen;
351  		/* Set number of unused bits to zero */
352		pub->public_key->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
353		pub->public_key->flags|=ASN1_STRING_FLAG_BITS_LEFT;
354		}
355	return 1;
356	}
357
358int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg,
359		const unsigned char **pk, int *ppklen,
360		X509_ALGOR **pa,
361		X509_PUBKEY *pub)
362	{
363	if (ppkalg)
364		*ppkalg = pub->algor->algorithm;
365	if (pk)
366		{
367		*pk = pub->public_key->data;
368		*ppklen = pub->public_key->length;
369		}
370	if (pa)
371		*pa = pub->algor;
372	return 1;
373	}
374