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