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