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