Switch version string to SSLeay/OpenSSL
[openssl.git] / crypto / pem / pem_info.c
1 /* crypto/pem/pem_info.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 "buffer.h"
62 #include "objects.h"
63 #include "evp.h"
64 #include "x509.h"
65 #include "pem.h"
66
67 #ifndef NO_FP_API
68 STACK *PEM_X509_INFO_read(fp,sk,cb)
69 FILE *fp;
70 STACK *sk;
71 int (*cb)();
72         {
73         BIO *b;
74         STACK *ret;
75
76         if ((b=BIO_new(BIO_s_file())) == NULL)
77                 {
78                 PEMerr(PEM_F_PEM_X509_INFO_READ,ERR_R_BUF_LIB);
79                 return(0);
80                 }
81         BIO_set_fp(b,fp,BIO_NOCLOSE);
82         ret=PEM_X509_INFO_read_bio(b,sk,cb);
83         BIO_free(b);
84         return(ret);
85         }
86 #endif
87
88 STACK *PEM_X509_INFO_read_bio(bp,sk,cb)
89 BIO *bp;
90 STACK *sk;
91 int (*cb)();
92         {
93         X509_INFO *xi=NULL;
94         char *name=NULL,*header=NULL,**pp;
95         unsigned char *data=NULL,*p;
96         long len,error=0;
97         int ok=0;
98         STACK *ret=NULL;
99         unsigned int i,raw;
100         char *(*d2i)();
101
102         if (sk == NULL)
103                 {
104                 if ((ret=sk_new_null()) == NULL)
105                         {
106                         PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_MALLOC_FAILURE);
107                         goto err;
108                         }
109                 }
110         else
111                 ret=sk;
112
113         if ((xi=X509_INFO_new()) == NULL) goto err;
114         for (;;)
115                 {
116                 raw=0;
117                 i=PEM_read_bio(bp,&name,&header,&data,&len);
118                 if (i == 0)
119                         {
120                         error=ERR_GET_REASON(ERR_peek_error());
121                         if (error == PEM_R_NO_START_LINE)
122                                 {
123                                 ERR_clear_error();
124                                 break;
125                                 }
126                         goto err;
127                         }
128 start:
129                 if (    (strcmp(name,PEM_STRING_X509) == 0) ||
130                         (strcmp(name,PEM_STRING_X509_OLD) == 0))
131                         {
132                         d2i=(char *(*)())d2i_X509;
133                         if (xi->x509 != NULL)
134                                 {
135                                 if (!sk_push(ret,(char *)xi)) goto err;
136                                 if ((xi=X509_INFO_new()) == NULL) goto err;
137                                 goto start;
138                                 }
139                         pp=(char **)&(xi->x509);
140                         }
141                 else if (strcmp(name,PEM_STRING_X509_CRL) == 0)
142                         {
143                         d2i=(char *(*)())d2i_X509_CRL;
144                         if (xi->crl != NULL)
145                                 {
146                                 if (!sk_push(ret,(char *)xi)) goto err;
147                                 if ((xi=X509_INFO_new()) == NULL) goto err;
148                                 goto start;
149                                 }
150                         pp=(char **)&(xi->crl);
151                         }
152                 else
153 #ifndef NO_RSA
154                         if (strcmp(name,PEM_STRING_RSA) == 0)
155                         {
156                         d2i=(char *(*)())d2i_RSAPrivateKey;
157                         if (xi->x_pkey != NULL) 
158                                 {
159                                 if (!sk_push(ret,(char *)xi)) goto err;
160                                 if ((xi=X509_INFO_new()) == NULL) goto err;
161                                 goto start;
162                                 }
163
164                         xi->enc_data=NULL;
165                         xi->enc_len=0;
166
167                         xi->x_pkey=X509_PKEY_new();
168                         if ((xi->x_pkey->dec_pkey=EVP_PKEY_new()) == NULL)
169                                 goto err;
170                         xi->x_pkey->dec_pkey->type=EVP_PKEY_RSA;
171                         pp=(char **)&(xi->x_pkey->dec_pkey->pkey.rsa);
172                         if ((int)strlen(header) > 10) /* assume encrypted */
173                                 raw=1;
174                         }
175                 else
176 #endif
177 #ifndef NO_DSA
178                         if (strcmp(name,PEM_STRING_DSA) == 0)
179                         {
180                         d2i=(char *(*)())d2i_DSAPrivateKey;
181                         if (xi->x_pkey != NULL) 
182                                 {
183                                 if (!sk_push(ret,(char *)xi)) goto err;
184                                 if ((xi=X509_INFO_new()) == NULL) goto err;
185                                 goto start;
186                                 }
187
188                         xi->enc_data=NULL;
189                         xi->enc_len=0;
190
191                         xi->x_pkey=X509_PKEY_new();
192                         if ((xi->x_pkey->dec_pkey=EVP_PKEY_new()) == NULL)
193                                 goto err;
194                         xi->x_pkey->dec_pkey->type=EVP_PKEY_DSA;
195                         pp=(char **)&(xi->x_pkey->dec_pkey->pkey.dsa);
196                         if ((int)strlen(header) > 10) /* assume encrypted */
197                                 raw=1;
198                         }
199                 else
200 #endif
201                         {
202                         d2i=NULL;
203                         pp=NULL;
204                         }
205
206                 if (d2i != NULL)
207                         {
208                         if (!raw)
209                                 {
210                                 EVP_CIPHER_INFO cipher;
211
212                                 if (!PEM_get_EVP_CIPHER_INFO(header,&cipher))
213                                         goto err;
214                                 if (!PEM_do_header(&cipher,data,&len,cb))
215                                         goto err;
216                                 p=data;
217                                 if (d2i(pp,&p,len) == NULL)
218                                         {
219                                         PEMerr(PEM_F_PEM_X509_INFO_READ_BIO,ERR_R_ASN1_LIB);
220                                         goto err;
221                                         }
222                                 }
223                         else
224                                 { /* encrypted RSA data */
225                                 if (!PEM_get_EVP_CIPHER_INFO(header,
226                                         &xi->enc_cipher)) goto err;
227                                 xi->enc_data=(char *)data;
228                                 xi->enc_len=(int)len;
229                                 data=NULL;
230                                 }
231                         }
232                 else    {
233                         /* unknown */
234                         }
235                 if (name != NULL) Free(name);
236                 if (header != NULL) Free(header);
237                 if (data != NULL) Free(data);
238                 name=NULL;
239                 header=NULL;
240                 data=NULL;
241                 }
242
243         /* if the last one hasn't been pushed yet and there is anything
244          * in it then add it to the stack ... 
245          */
246         if ((xi->x509 != NULL) || (xi->crl != NULL) ||
247                 (xi->x_pkey != NULL) || (xi->enc_data != NULL))
248                 {
249                 if (!sk_push(ret,(char *)xi)) goto err;
250                 xi=NULL;
251                 }
252         ok=1;
253 err:
254         if (xi != NULL) X509_INFO_free(xi);
255         if (!ok)
256                 {
257                 for (i=0; ((int)i)<sk_num(ret); i++)
258                         {
259                         xi=(X509_INFO *)sk_value(ret,i);
260                         X509_INFO_free(xi);
261                         }
262                 if (ret != sk) sk_free(ret);
263                 ret=NULL;
264                 }
265                 
266         if (name != NULL) Free(name);
267         if (header != NULL) Free(header);
268         if (data != NULL) Free(data);
269         return(ret);
270         }
271
272
273 /* A TJH addition */
274 int PEM_X509_INFO_write_bio(bp,xi,enc,kstr,klen,cb)
275 BIO *bp;
276 X509_INFO *xi;
277 EVP_CIPHER *enc;
278 unsigned char *kstr;
279 int klen;
280 int (*cb)();
281         {
282         EVP_CIPHER_CTX ctx;
283         int i,ret=0;
284         unsigned char *data=NULL;
285         char *objstr=NULL;
286 #define PEM_BUFSIZE     1024
287         char buf[PEM_BUFSIZE];
288         unsigned char *iv=NULL;
289         
290         if (enc != NULL)
291                 {
292                 objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
293                 if (objstr == NULL)
294                         {
295                         PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER);
296                         goto err;
297                         }
298                 }
299
300         /* now for the fun part ... if we have a private key then 
301          * we have to be able to handle a not-yet-decrypted key
302          * being written out correctly ... if it is decrypted or
303          * it is non-encrypted then we use the base code
304          */
305         if (xi->x_pkey!=NULL)
306                 {
307                 if ( (xi->enc_data!=NULL) && (xi->enc_len>0) )
308                         {
309                         /* copy from wierdo names into more normal things */
310                         iv=xi->enc_cipher.iv;
311                         data=(unsigned char *)xi->enc_data;
312                         i=xi->enc_len;
313
314                         /* we take the encryption data from the
315                          * internal stuff rather than what the
316                          * user has passed us ... as we have to 
317                          * match exactly for some strange reason
318                          */
319                         objstr=OBJ_nid2sn(
320                                 EVP_CIPHER_nid(xi->enc_cipher.cipher));
321                         if (objstr == NULL)
322                                 {
323                                 PEMerr(PEM_F_PEM_X509_INFO_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER);
324                                 goto err;
325                                 }
326
327                         /* create the right magic header stuff */
328                         buf[0]='\0';
329                         PEM_proc_type(buf,PEM_TYPE_ENCRYPTED);
330                         PEM_dek_info(buf,objstr,8,(char *)iv);
331
332                         /* use the normal code to write things out */
333                         i=PEM_write_bio(bp,PEM_STRING_RSA,buf,data,i);
334                         if (i <= 0) goto err;
335                         }
336                 else
337                         {
338                         /* Add DSA/DH */
339 #ifndef NO_RSA
340                         /* normal optionally encrypted stuff */
341                         if (PEM_write_bio_RSAPrivateKey(bp,
342                                 xi->x_pkey->dec_pkey->pkey.rsa,
343                                 enc,kstr,klen,cb)<=0)
344                                 goto err;
345 #endif
346                         }
347                 }
348
349         /* if we have a certificate then write it out now */
350         if ((xi->x509 != NULL) || (PEM_write_bio_X509(bp,xi->x509) <= 0))
351                 goto err;
352
353         /* we are ignoring anything else that is loaded into the X509_INFO
354          * structure for the moment ... as I don't need it so I'm not
355          * coding it here and Eric can do it when this makes it into the
356          * base library --tjh
357          */
358
359         ret=1;
360
361 err:
362         memset((char *)&ctx,0,sizeof(ctx));
363         memset(buf,0,PEM_BUFSIZE);
364         return(ret);
365         }