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