x_pubkey.c revision 160814
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		{
75		X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval;
76		EVP_PKEY_free(pubkey->pkey);
77		}
78	return 1;
79	}
80
81ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = {
82	ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR),
83	ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING)
84} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY)
85
86IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY)
87
88int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey)
89	{
90	X509_PUBKEY *pk=NULL;
91	X509_ALGOR *a;
92	ASN1_OBJECT *o;
93	unsigned char *s,*p = NULL;
94	int i;
95
96	if (x == NULL) return(0);
97
98	if ((pk=X509_PUBKEY_new()) == NULL) goto err;
99	a=pk->algor;
100
101	/* set the algorithm id */
102	if ((o=OBJ_nid2obj(pkey->type)) == NULL) goto err;
103	ASN1_OBJECT_free(a->algorithm);
104	a->algorithm=o;
105
106	/* Set the parameter list */
107	if (!pkey->save_parameters || (pkey->type == EVP_PKEY_RSA))
108		{
109		if ((a->parameter == NULL) ||
110			(a->parameter->type != V_ASN1_NULL))
111			{
112			ASN1_TYPE_free(a->parameter);
113			if (!(a->parameter=ASN1_TYPE_new()))
114				{
115				X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
116				goto err;
117				}
118			a->parameter->type=V_ASN1_NULL;
119			}
120		}
121#ifndef OPENSSL_NO_DSA
122	else if (pkey->type == EVP_PKEY_DSA)
123		{
124		unsigned char *pp;
125		DSA *dsa;
126
127		dsa=pkey->pkey.dsa;
128		dsa->write_params=0;
129		ASN1_TYPE_free(a->parameter);
130		if ((i=i2d_DSAparams(dsa,NULL)) <= 0)
131			goto err;
132		if (!(p=(unsigned char *)OPENSSL_malloc(i)))
133			{
134			X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
135			goto err;
136			}
137		pp=p;
138		i2d_DSAparams(dsa,&pp);
139		if (!(a->parameter=ASN1_TYPE_new()))
140			{
141			OPENSSL_free(p);
142			X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
143			goto err;
144			}
145		a->parameter->type=V_ASN1_SEQUENCE;
146		if (!(a->parameter->value.sequence=ASN1_STRING_new()))
147			{
148			OPENSSL_free(p);
149			X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
150			goto err;
151			}
152		if (!ASN1_STRING_set(a->parameter->value.sequence,p,i))
153			{
154			OPENSSL_free(p);
155			X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
156			goto err;
157			}
158		OPENSSL_free(p);
159		}
160#endif
161#ifndef OPENSSL_NO_EC
162	else if (pkey->type == EVP_PKEY_EC)
163		{
164		int nid=0;
165		unsigned char *pp;
166		EC_KEY *ec_key;
167		const EC_GROUP *group;
168
169		ec_key = pkey->pkey.ec;
170		ASN1_TYPE_free(a->parameter);
171
172		if ((a->parameter = ASN1_TYPE_new()) == NULL)
173			{
174			X509err(X509_F_X509_PUBKEY_SET, ERR_R_ASN1_LIB);
175			goto err;
176			}
177
178		group = EC_KEY_get0_group(ec_key);
179		if (EC_GROUP_get_asn1_flag(group)
180                     && (nid = EC_GROUP_get_curve_name(group)))
181			{
182			/* just set the OID */
183			a->parameter->type = V_ASN1_OBJECT;
184			a->parameter->value.object = OBJ_nid2obj(nid);
185			}
186		else /* explicit parameters */
187			{
188			if ((i = i2d_ECParameters(ec_key, NULL)) == 0)
189				{
190				X509err(X509_F_X509_PUBKEY_SET, ERR_R_EC_LIB);
191				goto err;
192				}
193			if ((p = (unsigned char *) OPENSSL_malloc(i)) == NULL)
194				{
195				X509err(X509_F_X509_PUBKEY_SET, ERR_R_MALLOC_FAILURE);
196				goto err;
197				}
198			pp = p;
199			if (!i2d_ECParameters(ec_key, &pp))
200				{
201				X509err(X509_F_X509_PUBKEY_SET, ERR_R_EC_LIB);
202				OPENSSL_free(p);
203				goto err;
204				}
205			a->parameter->type = V_ASN1_SEQUENCE;
206			if ((a->parameter->value.sequence = ASN1_STRING_new()) == NULL)
207				{
208				X509err(X509_F_X509_PUBKEY_SET, ERR_R_ASN1_LIB);
209				OPENSSL_free(p);
210				goto err;
211				}
212			ASN1_STRING_set(a->parameter->value.sequence, p, i);
213			OPENSSL_free(p);
214			}
215		}
216#endif
217	else if (1)
218		{
219		X509err(X509_F_X509_PUBKEY_SET,X509_R_UNSUPPORTED_ALGORITHM);
220		goto err;
221		}
222
223	if ((i=i2d_PublicKey(pkey,NULL)) <= 0) goto err;
224	if ((s=(unsigned char *)OPENSSL_malloc(i+1)) == NULL)
225		{
226		X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
227		goto err;
228		}
229	p=s;
230	i2d_PublicKey(pkey,&p);
231	if (!M_ASN1_BIT_STRING_set(pk->public_key,s,i))
232		{
233		X509err(X509_F_X509_PUBKEY_SET,ERR_R_MALLOC_FAILURE);
234		goto err;
235		}
236  	/* Set number of unused bits to zero */
237	pk->public_key->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07);
238	pk->public_key->flags|=ASN1_STRING_FLAG_BITS_LEFT;
239
240	OPENSSL_free(s);
241
242#if 0
243	CRYPTO_add(&pkey->references,1,CRYPTO_LOCK_EVP_PKEY);
244	pk->pkey=pkey;
245#endif
246
247	if (*x != NULL)
248		X509_PUBKEY_free(*x);
249
250	*x=pk;
251
252	return 1;
253err:
254	if (pk != NULL) X509_PUBKEY_free(pk);
255	return 0;
256	}
257
258EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key)
259	{
260	EVP_PKEY *ret=NULL;
261	long j;
262	int type;
263	const unsigned char *p;
264#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
265	const unsigned char *cp;
266	X509_ALGOR *a;
267#endif
268
269	if (key == NULL) goto err;
270
271	if (key->pkey != NULL)
272		{
273		CRYPTO_add(&key->pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
274		return(key->pkey);
275		}
276
277	if (key->public_key == NULL) goto err;
278
279	type=OBJ_obj2nid(key->algor->algorithm);
280	if ((ret = EVP_PKEY_new()) == NULL)
281		{
282		X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE);
283		goto err;
284		}
285	ret->type = EVP_PKEY_type(type);
286
287	/* the parameters must be extracted before the public key (ECDSA!) */
288
289#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
290	a=key->algor;
291#endif
292
293	if (0)
294		;
295#ifndef OPENSSL_NO_DSA
296	else if (ret->type == EVP_PKEY_DSA)
297		{
298		if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE))
299			{
300			if ((ret->pkey.dsa = DSA_new()) == NULL)
301				{
302				X509err(X509_F_X509_PUBKEY_GET, ERR_R_MALLOC_FAILURE);
303				goto err;
304				}
305			ret->pkey.dsa->write_params=0;
306			cp=p=a->parameter->value.sequence->data;
307			j=a->parameter->value.sequence->length;
308			if (!d2i_DSAparams(&ret->pkey.dsa, &cp, (long)j))
309				goto err;
310			}
311		ret->save_parameters=1;
312		}
313#endif
314#ifndef OPENSSL_NO_EC
315	else if (ret->type == EVP_PKEY_EC)
316		{
317		if (a->parameter && (a->parameter->type == V_ASN1_SEQUENCE))
318			{
319			/* type == V_ASN1_SEQUENCE => we have explicit parameters
320                         * (e.g. parameters in the X9_62_EC_PARAMETERS-structure )
321			 */
322			if ((ret->pkey.ec= EC_KEY_new()) == NULL)
323				{
324				X509err(X509_F_X509_PUBKEY_GET,
325					ERR_R_MALLOC_FAILURE);
326				goto err;
327				}
328			cp = p = a->parameter->value.sequence->data;
329			j = a->parameter->value.sequence->length;
330			if (!d2i_ECParameters(&ret->pkey.ec, &cp, (long)j))
331				{
332				X509err(X509_F_X509_PUBKEY_GET, ERR_R_EC_LIB);
333				goto err;
334				}
335			}
336		else if (a->parameter && (a->parameter->type == V_ASN1_OBJECT))
337			{
338			/* type == V_ASN1_OBJECT => the parameters are given
339			 * by an asn1 OID
340			 */
341			EC_KEY   *ec_key;
342			EC_GROUP *group;
343
344			if (ret->pkey.ec == NULL)
345				ret->pkey.ec = EC_KEY_new();
346			ec_key = ret->pkey.ec;
347			if (ec_key == NULL)
348				goto err;
349			group = EC_GROUP_new_by_curve_name(OBJ_obj2nid(a->parameter->value.object));
350			if (group == NULL)
351				goto err;
352			EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
353			if (EC_KEY_set_group(ec_key, group) == 0)
354				goto err;
355			EC_GROUP_free(group);
356			}
357			/* the case implicitlyCA is currently not implemented */
358		ret->save_parameters = 1;
359		}
360#endif
361
362	p=key->public_key->data;
363        j=key->public_key->length;
364        if (!d2i_PublicKey(type, &ret, &p, (long)j))
365		{
366		X509err(X509_F_X509_PUBKEY_GET, X509_R_ERR_ASN1_LIB);
367		goto err;
368		}
369
370	key->pkey = ret;
371	CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_EVP_PKEY);
372	return(ret);
373err:
374	if (ret != NULL)
375		EVP_PKEY_free(ret);
376	return(NULL);
377	}
378
379/* Now two pseudo ASN1 routines that take an EVP_PKEY structure
380 * and encode or decode as X509_PUBKEY
381 */
382
383EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp,
384	     long length)
385	{
386	X509_PUBKEY *xpk;
387	EVP_PKEY *pktmp;
388	xpk = d2i_X509_PUBKEY(NULL, pp, length);
389	if(!xpk) return NULL;
390	pktmp = X509_PUBKEY_get(xpk);
391	X509_PUBKEY_free(xpk);
392	if(!pktmp) return NULL;
393	if(a)
394		{
395		EVP_PKEY_free(*a);
396		*a = pktmp;
397		}
398	return pktmp;
399	}
400
401int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp)
402	{
403	X509_PUBKEY *xpk=NULL;
404	int ret;
405	if(!a) return 0;
406	if(!X509_PUBKEY_set(&xpk, a)) return 0;
407	ret = i2d_X509_PUBKEY(xpk, pp);
408	X509_PUBKEY_free(xpk);
409	return ret;
410	}
411
412/* The following are equivalents but which return RSA and DSA
413 * keys
414 */
415#ifndef OPENSSL_NO_RSA
416RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp,
417	     long length)
418	{
419	EVP_PKEY *pkey;
420	RSA *key;
421	const unsigned char *q;
422	q = *pp;
423	pkey = d2i_PUBKEY(NULL, &q, length);
424	if (!pkey) return NULL;
425	key = EVP_PKEY_get1_RSA(pkey);
426	EVP_PKEY_free(pkey);
427	if (!key) return NULL;
428	*pp = q;
429	if (a)
430		{
431		RSA_free(*a);
432		*a = key;
433		}
434	return key;
435	}
436
437int i2d_RSA_PUBKEY(RSA *a, unsigned char **pp)
438	{
439	EVP_PKEY *pktmp;
440	int ret;
441	if (!a) return 0;
442	pktmp = EVP_PKEY_new();
443	if (!pktmp)
444		{
445		ASN1err(ASN1_F_I2D_RSA_PUBKEY, ERR_R_MALLOC_FAILURE);
446		return 0;
447		}
448	EVP_PKEY_set1_RSA(pktmp, a);
449	ret = i2d_PUBKEY(pktmp, pp);
450	EVP_PKEY_free(pktmp);
451	return ret;
452	}
453#endif
454
455#ifndef OPENSSL_NO_DSA
456DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp,
457	     long length)
458	{
459	EVP_PKEY *pkey;
460	DSA *key;
461	const unsigned char *q;
462	q = *pp;
463	pkey = d2i_PUBKEY(NULL, &q, length);
464	if (!pkey) return NULL;
465	key = EVP_PKEY_get1_DSA(pkey);
466	EVP_PKEY_free(pkey);
467	if (!key) return NULL;
468	*pp = q;
469	if (a)
470		{
471		DSA_free(*a);
472		*a = key;
473		}
474	return key;
475	}
476
477int i2d_DSA_PUBKEY(DSA *a, unsigned char **pp)
478	{
479	EVP_PKEY *pktmp;
480	int ret;
481	if(!a) return 0;
482	pktmp = EVP_PKEY_new();
483	if(!pktmp)
484		{
485		ASN1err(ASN1_F_I2D_DSA_PUBKEY, ERR_R_MALLOC_FAILURE);
486		return 0;
487		}
488	EVP_PKEY_set1_DSA(pktmp, a);
489	ret = i2d_PUBKEY(pktmp, pp);
490	EVP_PKEY_free(pktmp);
491	return ret;
492	}
493#endif
494
495#ifndef OPENSSL_NO_EC
496EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length)
497	{
498	EVP_PKEY *pkey;
499	EC_KEY *key;
500	const unsigned char *q;
501	q = *pp;
502	pkey = d2i_PUBKEY(NULL, &q, length);
503	if (!pkey) return(NULL);
504	key = EVP_PKEY_get1_EC_KEY(pkey);
505	EVP_PKEY_free(pkey);
506	if (!key)  return(NULL);
507	*pp = q;
508	if (a)
509		{
510		EC_KEY_free(*a);
511		*a = key;
512		}
513	return(key);
514	}
515
516int i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp)
517	{
518	EVP_PKEY *pktmp;
519	int ret;
520	if (!a)	return(0);
521	if ((pktmp = EVP_PKEY_new()) == NULL)
522		{
523		ASN1err(ASN1_F_I2D_EC_PUBKEY, ERR_R_MALLOC_FAILURE);
524		return(0);
525		}
526	EVP_PKEY_set1_EC_KEY(pktmp, a);
527	ret = i2d_PUBKEY(pktmp, pp);
528	EVP_PKEY_free(pktmp);
529	return(ret);
530	}
531#endif
532