req.c revision 111147
155714Skris/* apps/req.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
855714Skris *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
1555714Skris *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
2255714Skris *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
3755714Skris * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
4055714Skris *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
5255714Skris *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include <stdlib.h>
6155714Skris#include <time.h>
6255714Skris#include <string.h>
63109998Smarkm#ifdef OPENSSL_NO_STDIO
6455714Skris#define APPS_WIN16
6555714Skris#endif
6655714Skris#include "apps.h"
6755714Skris#include <openssl/bio.h>
6855714Skris#include <openssl/evp.h>
6955714Skris#include <openssl/conf.h>
7055714Skris#include <openssl/err.h>
7155714Skris#include <openssl/asn1.h>
7255714Skris#include <openssl/x509.h>
7355714Skris#include <openssl/x509v3.h>
7455714Skris#include <openssl/objects.h>
7555714Skris#include <openssl/pem.h>
76109998Smarkm#include "../crypto/cryptlib.h"
7755714Skris
7855714Skris#define SECTION		"req"
7955714Skris
8055714Skris#define BITS		"default_bits"
8155714Skris#define KEYFILE		"default_keyfile"
8259191Skris#define PROMPT		"prompt"
8355714Skris#define DISTINGUISHED_NAME	"distinguished_name"
8455714Skris#define ATTRIBUTES	"attributes"
8555714Skris#define V3_EXTENSIONS	"x509_extensions"
8659191Skris#define REQ_EXTENSIONS	"req_extensions"
8759191Skris#define STRING_MASK	"string_mask"
88109998Smarkm#define UTF8_IN		"utf8"
8955714Skris
9055714Skris#define DEFAULT_KEY_LENGTH	512
9155714Skris#define MIN_KEY_LENGTH		384
9255714Skris
9355714Skris#undef PROG
9455714Skris#define PROG	req_main
9555714Skris
9659191Skris/* -inform arg	- input format - default PEM (DER or PEM)
9755714Skris * -outform arg - output format - default PEM
9855714Skris * -in arg	- input file - default stdin
9955714Skris * -out arg	- output file - default stdout
10055714Skris * -verify	- check request signature
10155714Skris * -noout	- don't print stuff out.
10255714Skris * -text	- print out human readable text.
10355714Skris * -nodes	- no des encryption
10455714Skris * -config file	- Load configuration file.
10555714Skris * -key file	- make a request using key in file (or use it for verification).
106109998Smarkm * -keyform arg	- key file format.
10768651Skris * -rand file(s) - load the file(s) into the PRNG.
10855714Skris * -newkey	- make a key and a request.
10955714Skris * -modulus	- print RSA modulus.
110109998Smarkm * -pubkey	- output Public Key.
11155714Skris * -x509	- output a self signed X509 structure instead.
11255714Skris * -asn1-kludge	- output new certificate request in a format that some CA's
11355714Skris *		  require.  This format is wrong
11455714Skris */
11555714Skris
116109998Smarkmstatic int make_REQ(X509_REQ *req,EVP_PKEY *pkey,char *dn,int attribs,
117109998Smarkm		unsigned long chtype);
118109998Smarkmstatic int build_subject(X509_REQ *req, char *subj, unsigned long chtype);
11959191Skrisstatic int prompt_info(X509_REQ *req,
12059191Skris		STACK_OF(CONF_VALUE) *dn_sk, char *dn_sect,
121109998Smarkm		STACK_OF(CONF_VALUE) *attr_sk, char *attr_sect, int attribs,
122109998Smarkm		unsigned long chtype);
12359191Skrisstatic int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *sk,
124109998Smarkm				STACK_OF(CONF_VALUE) *attr, int attribs,
125109998Smarkm				unsigned long chtype);
12659191Skrisstatic int add_attribute_object(X509_REQ *req, char *text,
127109998Smarkm				char *def, char *value, int nid, int n_min,
128109998Smarkm				int n_max, unsigned long chtype);
12955714Skrisstatic int add_DN_object(X509_NAME *n, char *text, char *def, char *value,
130109998Smarkm	int nid,int n_min,int n_max, unsigned long chtype);
131109998Smarkm#ifndef OPENSSL_NO_RSA
13255714Skrisstatic void MS_CALLBACK req_cb(int p,int n,void *arg);
13359191Skris#endif
134109998Smarkmstatic int req_check_len(int len,int n_min,int n_max);
13555714Skrisstatic int check_end(char *str, char *end);
13655714Skris#ifndef MONOLITH
13755714Skrisstatic char *default_config_file=NULL;
13855714Skris#endif
139109998Smarkmstatic CONF *req_conf=NULL;
140109998Smarkmstatic int batch=0;
14155714Skris
14255714Skris#define TYPE_RSA	1
14355714Skris#define TYPE_DSA	2
14455714Skris#define TYPE_DH		3
14555714Skris
14659191Skrisint MAIN(int, char **);
14759191Skris
14855714Skrisint MAIN(int argc, char **argv)
14955714Skris	{
150109998Smarkm	ENGINE *e = NULL;
151109998Smarkm#ifndef OPENSSL_NO_DSA
15255714Skris	DSA *dsa_params=NULL;
15355714Skris#endif
154109998Smarkm	unsigned long nmflag = 0, reqflag = 0;
15555714Skris	int ex=1,x509=0,days=30;
15655714Skris	X509 *x509ss=NULL;
15755714Skris	X509_REQ *req=NULL;
15855714Skris	EVP_PKEY *pkey=NULL;
159109998Smarkm	int i=0,badops=0,newreq=0,verbose=0,pkey_type=TYPE_RSA;
160109998Smarkm	long newkey = -1;
16155714Skris	BIO *in=NULL,*out=NULL;
16255714Skris	int informat,outformat,verify=0,noout=0,text=0,keyform=FORMAT_PEM;
163109998Smarkm	int nodes=0,kludge=0,newhdr=0,subject=0,pubkey=0;
16455714Skris	char *infile,*outfile,*prog,*keyfile=NULL,*template=NULL,*keyout=NULL;
165111147Snectar#ifndef OPENSSL_NO_ENGINE
166109998Smarkm	char *engine=NULL;
167111147Snectar#endif
16855714Skris	char *extensions = NULL;
16959191Skris	char *req_exts = NULL;
170109998Smarkm	const EVP_CIPHER *cipher=NULL;
171109998Smarkm	ASN1_INTEGER *serial = NULL;
17255714Skris	int modulus=0;
17368651Skris	char *inrand=NULL;
17459191Skris	char *passargin = NULL, *passargout = NULL;
17559191Skris	char *passin = NULL, *passout = NULL;
17655714Skris	char *p;
177109998Smarkm	char *subj = NULL;
17855714Skris	const EVP_MD *md_alg=NULL,*digest=EVP_md5();
179109998Smarkm	unsigned long chtype = MBSTRING_ASC;
18055714Skris#ifndef MONOLITH
181109998Smarkm	char *to_free;
182109998Smarkm	long errline;
18355714Skris#endif
18455714Skris
18559191Skris	req_conf = NULL;
186109998Smarkm#ifndef OPENSSL_NO_DES
18755714Skris	cipher=EVP_des_ede3_cbc();
18855714Skris#endif
18955714Skris	apps_startup();
19055714Skris
19155714Skris	if (bio_err == NULL)
19255714Skris		if ((bio_err=BIO_new(BIO_s_file())) != NULL)
19355714Skris			BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
19455714Skris
19555714Skris	infile=NULL;
19655714Skris	outfile=NULL;
19755714Skris	informat=FORMAT_PEM;
19855714Skris	outformat=FORMAT_PEM;
19955714Skris
20055714Skris	prog=argv[0];
20155714Skris	argc--;
20255714Skris	argv++;
20355714Skris	while (argc >= 1)
20455714Skris		{
20555714Skris		if 	(strcmp(*argv,"-inform") == 0)
20655714Skris			{
20755714Skris			if (--argc < 1) goto bad;
20855714Skris			informat=str2fmt(*(++argv));
20955714Skris			}
21055714Skris		else if (strcmp(*argv,"-outform") == 0)
21155714Skris			{
21255714Skris			if (--argc < 1) goto bad;
21355714Skris			outformat=str2fmt(*(++argv));
21455714Skris			}
215111147Snectar#ifndef OPENSSL_NO_ENGINE
216109998Smarkm		else if (strcmp(*argv,"-engine") == 0)
217109998Smarkm			{
218109998Smarkm			if (--argc < 1) goto bad;
219109998Smarkm			engine= *(++argv);
220109998Smarkm			}
221111147Snectar#endif
22255714Skris		else if (strcmp(*argv,"-key") == 0)
22355714Skris			{
22455714Skris			if (--argc < 1) goto bad;
22555714Skris			keyfile= *(++argv);
22655714Skris			}
227109998Smarkm		else if (strcmp(*argv,"-pubkey") == 0)
228109998Smarkm			{
229109998Smarkm			pubkey=1;
230109998Smarkm			}
23155714Skris		else if (strcmp(*argv,"-new") == 0)
23255714Skris			{
23355714Skris			newreq=1;
23455714Skris			}
23555714Skris		else if (strcmp(*argv,"-config") == 0)
23655714Skris			{
23755714Skris			if (--argc < 1) goto bad;
23855714Skris			template= *(++argv);
23955714Skris			}
24055714Skris		else if (strcmp(*argv,"-keyform") == 0)
24155714Skris			{
24255714Skris			if (--argc < 1) goto bad;
24355714Skris			keyform=str2fmt(*(++argv));
24455714Skris			}
24555714Skris		else if (strcmp(*argv,"-in") == 0)
24655714Skris			{
24755714Skris			if (--argc < 1) goto bad;
24855714Skris			infile= *(++argv);
24955714Skris			}
25055714Skris		else if (strcmp(*argv,"-out") == 0)
25155714Skris			{
25255714Skris			if (--argc < 1) goto bad;
25355714Skris			outfile= *(++argv);
25455714Skris			}
25555714Skris		else if (strcmp(*argv,"-keyout") == 0)
25655714Skris			{
25755714Skris			if (--argc < 1) goto bad;
25855714Skris			keyout= *(++argv);
25955714Skris			}
26059191Skris		else if (strcmp(*argv,"-passin") == 0)
26159191Skris			{
26259191Skris			if (--argc < 1) goto bad;
26359191Skris			passargin= *(++argv);
26459191Skris			}
26559191Skris		else if (strcmp(*argv,"-passout") == 0)
26659191Skris			{
26759191Skris			if (--argc < 1) goto bad;
26859191Skris			passargout= *(++argv);
26959191Skris			}
27068651Skris		else if (strcmp(*argv,"-rand") == 0)
27168651Skris			{
27268651Skris			if (--argc < 1) goto bad;
27368651Skris			inrand= *(++argv);
27468651Skris			}
27555714Skris		else if (strcmp(*argv,"-newkey") == 0)
27655714Skris			{
27755714Skris			int is_numeric;
27855714Skris
27955714Skris			if (--argc < 1) goto bad;
28055714Skris			p= *(++argv);
28155714Skris			is_numeric = p[0] >= '0' && p[0] <= '9';
28255714Skris			if (strncmp("rsa:",p,4) == 0 || is_numeric)
28355714Skris				{
28455714Skris				pkey_type=TYPE_RSA;
28555714Skris				if(!is_numeric)
28655714Skris				    p+=4;
28755714Skris				newkey= atoi(p);
28855714Skris				}
28955714Skris			else
290109998Smarkm#ifndef OPENSSL_NO_DSA
29155714Skris				if (strncmp("dsa:",p,4) == 0)
29255714Skris				{
29355714Skris				X509 *xtmp=NULL;
29455714Skris				EVP_PKEY *dtmp;
29555714Skris
29655714Skris				pkey_type=TYPE_DSA;
29755714Skris				p+=4;
29855714Skris				if ((in=BIO_new_file(p,"r")) == NULL)
29955714Skris					{
30055714Skris					perror(p);
30155714Skris					goto end;
30255714Skris					}
30355714Skris				if ((dsa_params=PEM_read_bio_DSAparams(in,NULL,NULL,NULL)) == NULL)
30455714Skris					{
30555714Skris					ERR_clear_error();
30655714Skris					(void)BIO_reset(in);
30755714Skris					if ((xtmp=PEM_read_bio_X509(in,NULL,NULL,NULL)) == NULL)
30855714Skris						{
30955714Skris						BIO_printf(bio_err,"unable to load DSA parameters from file\n");
31055714Skris						goto end;
31155714Skris						}
31255714Skris
313100928Snectar					if ((dtmp=X509_get_pubkey(xtmp)) == NULL) goto end;
31455714Skris					if (dtmp->type == EVP_PKEY_DSA)
31555714Skris						dsa_params=DSAparams_dup(dtmp->pkey.dsa);
31655714Skris					EVP_PKEY_free(dtmp);
31755714Skris					X509_free(xtmp);
31855714Skris					if (dsa_params == NULL)
31955714Skris						{
32055714Skris						BIO_printf(bio_err,"Certificate does not contain DSA parameters\n");
32155714Skris						goto end;
32255714Skris						}
32355714Skris					}
32455714Skris				BIO_free(in);
32555714Skris				newkey=BN_num_bits(dsa_params->p);
32655714Skris				in=NULL;
32755714Skris				}
32855714Skris			else
32955714Skris#endif
330109998Smarkm#ifndef OPENSSL_NO_DH
33155714Skris				if (strncmp("dh:",p,4) == 0)
33255714Skris				{
33355714Skris				pkey_type=TYPE_DH;
33455714Skris				p+=3;
33555714Skris				}
33655714Skris			else
33755714Skris#endif
33855714Skris				pkey_type=TYPE_RSA;
33955714Skris
34055714Skris			newreq=1;
34155714Skris			}
342109998Smarkm		else if (strcmp(*argv,"-batch") == 0)
343109998Smarkm			batch=1;
34459191Skris		else if (strcmp(*argv,"-newhdr") == 0)
34559191Skris			newhdr=1;
34655714Skris		else if (strcmp(*argv,"-modulus") == 0)
34755714Skris			modulus=1;
34855714Skris		else if (strcmp(*argv,"-verify") == 0)
34955714Skris			verify=1;
35055714Skris		else if (strcmp(*argv,"-nodes") == 0)
35155714Skris			nodes=1;
35255714Skris		else if (strcmp(*argv,"-noout") == 0)
35355714Skris			noout=1;
354109998Smarkm		else if (strcmp(*argv,"-verbose") == 0)
355109998Smarkm			verbose=1;
356109998Smarkm		else if (strcmp(*argv,"-utf8") == 0)
357109998Smarkm			chtype = MBSTRING_UTF8;
358109998Smarkm		else if (strcmp(*argv,"-nameopt") == 0)
359109998Smarkm			{
360109998Smarkm			if (--argc < 1) goto bad;
361109998Smarkm			if (!set_name_ex(&nmflag, *(++argv))) goto bad;
362109998Smarkm			}
363109998Smarkm		else if (strcmp(*argv,"-reqopt") == 0)
364109998Smarkm			{
365109998Smarkm			if (--argc < 1) goto bad;
366109998Smarkm			if (!set_cert_ex(&reqflag, *(++argv))) goto bad;
367109998Smarkm			}
368109998Smarkm		else if (strcmp(*argv,"-subject") == 0)
369109998Smarkm			subject=1;
37055714Skris		else if (strcmp(*argv,"-text") == 0)
37155714Skris			text=1;
37255714Skris		else if (strcmp(*argv,"-x509") == 0)
37355714Skris			x509=1;
37455714Skris		else if (strcmp(*argv,"-asn1-kludge") == 0)
37555714Skris			kludge=1;
37655714Skris		else if (strcmp(*argv,"-no-asn1-kludge") == 0)
37755714Skris			kludge=0;
378109998Smarkm		else if (strcmp(*argv,"-subj") == 0)
379109998Smarkm			{
380109998Smarkm			if (--argc < 1) goto bad;
381109998Smarkm			subj= *(++argv);
382109998Smarkm			}
38355714Skris		else if (strcmp(*argv,"-days") == 0)
38455714Skris			{
38555714Skris			if (--argc < 1) goto bad;
38655714Skris			days= atoi(*(++argv));
38755714Skris			if (days == 0) days=30;
38855714Skris			}
389109998Smarkm		else if (strcmp(*argv,"-set_serial") == 0)
390109998Smarkm			{
391109998Smarkm			if (--argc < 1) goto bad;
392109998Smarkm			serial = s2i_ASN1_INTEGER(NULL, *(++argv));
393109998Smarkm			if (!serial) goto bad;
394109998Smarkm			}
39555714Skris		else if ((md_alg=EVP_get_digestbyname(&((*argv)[1]))) != NULL)
39655714Skris			{
39755714Skris			/* ok */
39855714Skris			digest=md_alg;
39955714Skris			}
40059191Skris		else if (strcmp(*argv,"-extensions") == 0)
40159191Skris			{
40259191Skris			if (--argc < 1) goto bad;
40359191Skris			extensions = *(++argv);
40459191Skris			}
40559191Skris		else if (strcmp(*argv,"-reqexts") == 0)
40659191Skris			{
40759191Skris			if (--argc < 1) goto bad;
40859191Skris			req_exts = *(++argv);
40959191Skris			}
41055714Skris		else
41155714Skris			{
41255714Skris			BIO_printf(bio_err,"unknown option %s\n",*argv);
41355714Skris			badops=1;
41455714Skris			break;
41555714Skris			}
41655714Skris		argc--;
41755714Skris		argv++;
41855714Skris		}
41955714Skris
42055714Skris	if (badops)
42155714Skris		{
42255714Skrisbad:
42355714Skris		BIO_printf(bio_err,"%s [options] <infile >outfile\n",prog);
42455714Skris		BIO_printf(bio_err,"where options  are\n");
42559191Skris		BIO_printf(bio_err," -inform arg    input format - DER or PEM\n");
42659191Skris		BIO_printf(bio_err," -outform arg   output format - DER or PEM\n");
42755714Skris		BIO_printf(bio_err," -in arg        input file\n");
42855714Skris		BIO_printf(bio_err," -out arg       output file\n");
42955714Skris		BIO_printf(bio_err," -text          text form of request\n");
430109998Smarkm		BIO_printf(bio_err," -pubkey        output public key\n");
43155714Skris		BIO_printf(bio_err," -noout         do not output REQ\n");
43255714Skris		BIO_printf(bio_err," -verify        verify signature on REQ\n");
43355714Skris		BIO_printf(bio_err," -modulus       RSA modulus\n");
43455714Skris		BIO_printf(bio_err," -nodes         don't encrypt the output key\n");
435111147Snectar#ifndef OPENSSL_NO_ENGINE
436109998Smarkm		BIO_printf(bio_err," -engine e      use engine e, possibly a hardware device\n");
437111147Snectar#endif
438109998Smarkm		BIO_printf(bio_err," -subject       output the request's subject\n");
439109998Smarkm		BIO_printf(bio_err," -passin        private key password source\n");
440109998Smarkm		BIO_printf(bio_err," -key file      use the private key contained in file\n");
44155714Skris		BIO_printf(bio_err," -keyform arg   key file format\n");
44255714Skris		BIO_printf(bio_err," -keyout arg    file to send the key to\n");
44368651Skris		BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR);
44468651Skris		BIO_printf(bio_err,"                load the file (or the files in the directory) into\n");
44568651Skris		BIO_printf(bio_err,"                the random number generator\n");
44655714Skris		BIO_printf(bio_err," -newkey rsa:bits generate a new RSA key of 'bits' in size\n");
44755714Skris		BIO_printf(bio_err," -newkey dsa:file generate a new DSA key, parameters taken from CA in 'file'\n");
44889837Skris		BIO_printf(bio_err," -[digest]      Digest to sign with (md5, sha1, md2, mdc2, md4)\n");
44955714Skris		BIO_printf(bio_err," -config file   request template file.\n");
450109998Smarkm		BIO_printf(bio_err," -subj arg      set or modify request subject\n");
45155714Skris		BIO_printf(bio_err," -new           new request.\n");
452109998Smarkm		BIO_printf(bio_err," -batch         do not ask anything during request generation\n");
45355714Skris		BIO_printf(bio_err," -x509          output a x509 structure instead of a cert. req.\n");
454109998Smarkm		BIO_printf(bio_err," -days          number of days a certificate generated by -x509 is valid for.\n");
455109998Smarkm		BIO_printf(bio_err," -set_serial    serial number to use for a certificate generated by -x509.\n");
45659191Skris		BIO_printf(bio_err," -newhdr        output \"NEW\" in the header lines\n");
45755714Skris		BIO_printf(bio_err," -asn1-kludge   Output the 'request' in a format that is wrong but some CA's\n");
45855714Skris		BIO_printf(bio_err,"                have been reported as requiring\n");
45959191Skris		BIO_printf(bio_err," -extensions .. specify certificate extension section (override value in config file)\n");
46059191Skris		BIO_printf(bio_err," -reqexts ..    specify request extension section (override value in config file)\n");
461109998Smarkm		BIO_printf(bio_err," -utf8          input characters are UTF8 (default ASCII)\n");
462111147Snectar		BIO_printf(bio_err," -nameopt arg    - various certificate name options\n");
463109998Smarkm		BIO_printf(bio_err," -reqopt arg    - various request text options\n\n");
46455714Skris		goto end;
46555714Skris		}
46655714Skris
46755714Skris	ERR_load_crypto_strings();
46859191Skris	if(!app_passwd(bio_err, passargin, passargout, &passin, &passout)) {
46959191Skris		BIO_printf(bio_err, "Error getting passwords\n");
47059191Skris		goto end;
47159191Skris	}
47255714Skris
47359191Skris#ifndef MONOLITH /* else this has happened in openssl.c (global `config') */
47455714Skris	/* Lets load up our environment a little */
47555714Skris	p=getenv("OPENSSL_CONF");
47655714Skris	if (p == NULL)
47755714Skris		p=getenv("SSLEAY_CONF");
47855714Skris	if (p == NULL)
479109998Smarkm		p=to_free=make_config_name();
48059191Skris	default_config_file=p;
481109998Smarkm	config=NCONF_new(NULL);
482109998Smarkm	i=NCONF_load(config, p, &errline);
48355714Skris#endif
48455714Skris
48555714Skris	if (template != NULL)
48655714Skris		{
487109998Smarkm		long errline = -1;
48855714Skris
489109998Smarkm		if( verbose )
490109998Smarkm			BIO_printf(bio_err,"Using configuration from %s\n",template);
491109998Smarkm		req_conf=NCONF_new(NULL);
492109998Smarkm		i=NCONF_load(req_conf,template,&errline);
493109998Smarkm		if (i == 0)
49455714Skris			{
49555714Skris			BIO_printf(bio_err,"error on line %ld of %s\n",errline,template);
49655714Skris			goto end;
49755714Skris			}
49855714Skris		}
49955714Skris	else
50055714Skris		{
50155714Skris		req_conf=config;
502109998Smarkm		if( verbose )
503109998Smarkm			BIO_printf(bio_err,"Using configuration from %s\n",
50455714Skris			default_config_file);
50555714Skris		if (req_conf == NULL)
50655714Skris			{
50755714Skris			BIO_printf(bio_err,"Unable to load config info\n");
50855714Skris			}
50955714Skris		}
51055714Skris
51155714Skris	if (req_conf != NULL)
51255714Skris		{
513109998Smarkm		if (!load_config(bio_err, req_conf))
514109998Smarkm			goto end;
515109998Smarkm		p=NCONF_get_string(req_conf,NULL,"oid_file");
516109998Smarkm		if (p == NULL)
517109998Smarkm			ERR_clear_error();
51855714Skris		if (p != NULL)
51955714Skris			{
52055714Skris			BIO *oid_bio;
52155714Skris
52255714Skris			oid_bio=BIO_new_file(p,"r");
52355714Skris			if (oid_bio == NULL)
52455714Skris				{
52555714Skris				/*
52655714Skris				BIO_printf(bio_err,"problems opening %s for extra oid's\n",p);
52755714Skris				ERR_print_errors(bio_err);
52855714Skris				*/
52955714Skris				}
53055714Skris			else
53155714Skris				{
53255714Skris				OBJ_create_objects(oid_bio);
53355714Skris				BIO_free(oid_bio);
53455714Skris				}
53555714Skris			}
53655714Skris		}
537109998Smarkm	if(!add_oid_section(bio_err, req_conf)) goto end;
53855714Skris
539109998Smarkm	if (md_alg == NULL)
54055714Skris		{
541109998Smarkm		p=NCONF_get_string(req_conf,SECTION,"default_md");
542109998Smarkm		if (p == NULL)
543109998Smarkm			ERR_clear_error();
544109998Smarkm		if (p != NULL)
545109998Smarkm			{
546109998Smarkm			if ((md_alg=EVP_get_digestbyname(p)) != NULL)
547109998Smarkm				digest=md_alg;
548109998Smarkm			}
54955714Skris		}
55055714Skris
551109998Smarkm	if (!extensions)
552109998Smarkm		{
553109998Smarkm		extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS);
554109998Smarkm		if (!extensions)
555109998Smarkm			ERR_clear_error();
556109998Smarkm		}
557109998Smarkm	if (extensions) {
55855714Skris		/* Check syntax of file */
55955714Skris		X509V3_CTX ctx;
56055714Skris		X509V3_set_ctx_test(&ctx);
561109998Smarkm		X509V3_set_nconf(&ctx, req_conf);
562109998Smarkm		if(!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) {
56355714Skris			BIO_printf(bio_err,
56455714Skris			 "Error Loading extension section %s\n", extensions);
56555714Skris			goto end;
56655714Skris		}
56755714Skris	}
56855714Skris
56959191Skris	if(!passin)
570109998Smarkm		{
571109998Smarkm		passin = NCONF_get_string(req_conf, SECTION, "input_password");
572109998Smarkm		if (!passin)
573109998Smarkm			ERR_clear_error();
574109998Smarkm		}
575109998Smarkm
57659191Skris	if(!passout)
577109998Smarkm		{
578109998Smarkm		passout = NCONF_get_string(req_conf, SECTION, "output_password");
579109998Smarkm		if (!passout)
580109998Smarkm			ERR_clear_error();
581109998Smarkm		}
58259191Skris
583109998Smarkm	p = NCONF_get_string(req_conf, SECTION, STRING_MASK);
584109998Smarkm	if (!p)
585109998Smarkm		ERR_clear_error();
58659191Skris
58759191Skris	if(p && !ASN1_STRING_set_default_mask_asc(p)) {
58859191Skris		BIO_printf(bio_err, "Invalid global string mask setting %s\n", p);
58959191Skris		goto end;
59059191Skris	}
59159191Skris
592109998Smarkm	if (chtype != MBSTRING_UTF8)
593109998Smarkm		{
594109998Smarkm		p = NCONF_get_string(req_conf, SECTION, UTF8_IN);
595109998Smarkm		if (!p)
596109998Smarkm			ERR_clear_error();
597109998Smarkm		else if (!strcmp(p, "yes"))
598109998Smarkm			chtype = MBSTRING_UTF8;
599109998Smarkm		}
600109998Smarkm
601109998Smarkm
60259191Skris	if(!req_exts)
603109998Smarkm		{
604109998Smarkm		req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS);
605109998Smarkm		if (!req_exts)
606109998Smarkm			ERR_clear_error();
607109998Smarkm		}
60859191Skris	if(req_exts) {
60959191Skris		/* Check syntax of file */
61059191Skris		X509V3_CTX ctx;
61159191Skris		X509V3_set_ctx_test(&ctx);
612109998Smarkm		X509V3_set_nconf(&ctx, req_conf);
613109998Smarkm		if(!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) {
61459191Skris			BIO_printf(bio_err,
61559191Skris			 "Error Loading request extension section %s\n",
61659191Skris								req_exts);
61759191Skris			goto end;
61859191Skris		}
61959191Skris	}
62059191Skris
62155714Skris	in=BIO_new(BIO_s_file());
62255714Skris	out=BIO_new(BIO_s_file());
62355714Skris	if ((in == NULL) || (out == NULL))
62455714Skris		goto end;
62555714Skris
626111147Snectar#ifndef OPENSSL_NO_ENGINE
627109998Smarkm        e = setup_engine(bio_err, engine, 0);
628111147Snectar#endif
629109998Smarkm
63055714Skris	if (keyfile != NULL)
63155714Skris		{
632109998Smarkm		pkey = load_key(bio_err, keyfile, keyform, 0, passin, e,
633109998Smarkm			"Private Key");
634109998Smarkm		if (!pkey)
63555714Skris			{
636109998Smarkm			/* load_key() has already printed an appropriate
637109998Smarkm			   message */
63855714Skris			goto end;
63955714Skris			}
640109998Smarkm		if (EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA)
64159191Skris			{
642109998Smarkm			char *randfile = NCONF_get_string(req_conf,SECTION,"RANDFILE");
643109998Smarkm			if (randfile == NULL)
644109998Smarkm				ERR_clear_error();
645109998Smarkm			app_RAND_load_file(randfile, bio_err, 0);
64659191Skris			}
64755714Skris		}
64855714Skris
64955714Skris	if (newreq && (pkey == NULL))
65055714Skris		{
651109998Smarkm		char *randfile = NCONF_get_string(req_conf,SECTION,"RANDFILE");
652109998Smarkm		if (randfile == NULL)
653109998Smarkm			ERR_clear_error();
65459191Skris		app_RAND_load_file(randfile, bio_err, 0);
65568651Skris		if (inrand)
65668651Skris			app_RAND_load_files(inrand);
65759191Skris
65855714Skris		if (newkey <= 0)
65955714Skris			{
660109998Smarkm			if (!NCONF_get_number(req_conf,SECTION,BITS, &newkey))
66155714Skris				newkey=DEFAULT_KEY_LENGTH;
66255714Skris			}
66355714Skris
66455714Skris		if (newkey < MIN_KEY_LENGTH)
66555714Skris			{
66655714Skris			BIO_printf(bio_err,"private key length is too short,\n");
66755714Skris			BIO_printf(bio_err,"it needs to be at least %d bits, not %d\n",MIN_KEY_LENGTH,newkey);
66855714Skris			goto end;
66955714Skris			}
67055714Skris		BIO_printf(bio_err,"Generating a %d bit %s private key\n",
67155714Skris			newkey,(pkey_type == TYPE_RSA)?"RSA":"DSA");
67255714Skris
67355714Skris		if ((pkey=EVP_PKEY_new()) == NULL) goto end;
67455714Skris
675109998Smarkm#ifndef OPENSSL_NO_RSA
67655714Skris		if (pkey_type == TYPE_RSA)
67755714Skris			{
67855714Skris			if (!EVP_PKEY_assign_RSA(pkey,
67955714Skris				RSA_generate_key(newkey,0x10001,
68055714Skris					req_cb,bio_err)))
68155714Skris				goto end;
68255714Skris			}
68355714Skris		else
68455714Skris#endif
685109998Smarkm#ifndef OPENSSL_NO_DSA
68655714Skris			if (pkey_type == TYPE_DSA)
68755714Skris			{
68855714Skris			if (!DSA_generate_key(dsa_params)) goto end;
68955714Skris			if (!EVP_PKEY_assign_DSA(pkey,dsa_params)) goto end;
69055714Skris			dsa_params=NULL;
69155714Skris			}
69255714Skris#endif
69355714Skris
69459191Skris		app_RAND_write_file(randfile, bio_err);
69555714Skris
69655714Skris		if (pkey == NULL) goto end;
69755714Skris
69855714Skris		if (keyout == NULL)
699109998Smarkm			{
700109998Smarkm			keyout=NCONF_get_string(req_conf,SECTION,KEYFILE);
701109998Smarkm			if (keyout == NULL)
702109998Smarkm				ERR_clear_error();
703109998Smarkm			}
704109998Smarkm
70555714Skris		if (keyout == NULL)
70655714Skris			{
70755714Skris			BIO_printf(bio_err,"writing new private key to stdout\n");
70855714Skris			BIO_set_fp(out,stdout,BIO_NOCLOSE);
709109998Smarkm#ifdef OPENSSL_SYS_VMS
71068651Skris			{
71168651Skris			BIO *tmpbio = BIO_new(BIO_f_linebuffer());
71268651Skris			out = BIO_push(tmpbio, out);
71355714Skris			}
71468651Skris#endif
71568651Skris			}
71655714Skris		else
71755714Skris			{
71855714Skris			BIO_printf(bio_err,"writing new private key to '%s'\n",keyout);
71955714Skris			if (BIO_write_filename(out,keyout) <= 0)
72055714Skris				{
72155714Skris				perror(keyout);
72255714Skris				goto end;
72355714Skris				}
72455714Skris			}
72555714Skris
726109998Smarkm		p=NCONF_get_string(req_conf,SECTION,"encrypt_rsa_key");
72755714Skris		if (p == NULL)
728109998Smarkm			{
729109998Smarkm			ERR_clear_error();
730109998Smarkm			p=NCONF_get_string(req_conf,SECTION,"encrypt_key");
731109998Smarkm			if (p == NULL)
732109998Smarkm				ERR_clear_error();
733109998Smarkm			}
73455714Skris		if ((p != NULL) && (strcmp(p,"no") == 0))
73555714Skris			cipher=NULL;
73655714Skris		if (nodes) cipher=NULL;
73755714Skris
73855714Skris		i=0;
73955714Skrisloop:
74055714Skris		if (!PEM_write_bio_PrivateKey(out,pkey,cipher,
74159191Skris			NULL,0,NULL,passout))
74255714Skris			{
74355714Skris			if ((ERR_GET_REASON(ERR_peek_error()) ==
74455714Skris				PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3))
74555714Skris				{
74655714Skris				ERR_clear_error();
74755714Skris				i++;
74855714Skris				goto loop;
74955714Skris				}
75055714Skris			goto end;
75155714Skris			}
75255714Skris		BIO_printf(bio_err,"-----\n");
75355714Skris		}
75455714Skris
75555714Skris	if (!newreq)
75655714Skris		{
75755714Skris		/* Since we are using a pre-existing certificate
75855714Skris		 * request, the kludge 'format' info should not be
75955714Skris		 * changed. */
76055714Skris		kludge= -1;
76155714Skris		if (infile == NULL)
76255714Skris			BIO_set_fp(in,stdin,BIO_NOCLOSE);
76355714Skris		else
76455714Skris			{
76555714Skris			if (BIO_read_filename(in,infile) <= 0)
76655714Skris				{
76755714Skris				perror(infile);
76855714Skris				goto end;
76955714Skris				}
77055714Skris			}
77155714Skris
77255714Skris		if	(informat == FORMAT_ASN1)
77355714Skris			req=d2i_X509_REQ_bio(in,NULL);
77455714Skris		else if (informat == FORMAT_PEM)
77555714Skris			req=PEM_read_bio_X509_REQ(in,NULL,NULL,NULL);
77655714Skris		else
77755714Skris			{
77855714Skris			BIO_printf(bio_err,"bad input format specified for X509 request\n");
77955714Skris			goto end;
78055714Skris			}
78155714Skris		if (req == NULL)
78255714Skris			{
78355714Skris			BIO_printf(bio_err,"unable to load X509 request\n");
78455714Skris			goto end;
78555714Skris			}
78655714Skris		}
78755714Skris
78855714Skris	if (newreq || x509)
78955714Skris		{
79055714Skris		if (pkey == NULL)
79155714Skris			{
79255714Skris			BIO_printf(bio_err,"you need to specify a private key\n");
79355714Skris			goto end;
79455714Skris			}
795109998Smarkm#ifndef OPENSSL_NO_DSA
79672613Skris		if (pkey->type == EVP_PKEY_DSA)
79772613Skris			digest=EVP_dss1();
79872613Skris#endif
79955714Skris		if (req == NULL)
80055714Skris			{
80155714Skris			req=X509_REQ_new();
80255714Skris			if (req == NULL)
80355714Skris				{
80455714Skris				goto end;
80555714Skris				}
80655714Skris
807109998Smarkm			i=make_REQ(req,pkey,subj,!x509, chtype);
808109998Smarkm			subj=NULL; /* done processing '-subj' option */
809109998Smarkm			if ((kludge > 0) && !sk_X509_ATTRIBUTE_num(req->req_info->attributes))
810109998Smarkm				{
811109998Smarkm				sk_X509_ATTRIBUTE_free(req->req_info->attributes);
812109998Smarkm				req->req_info->attributes = NULL;
813109998Smarkm				}
81455714Skris			if (!i)
81555714Skris				{
81655714Skris				BIO_printf(bio_err,"problems making Certificate Request\n");
81755714Skris				goto end;
81855714Skris				}
81955714Skris			}
82055714Skris		if (x509)
82155714Skris			{
82255714Skris			EVP_PKEY *tmppkey;
82355714Skris			X509V3_CTX ext_ctx;
82455714Skris			if ((x509ss=X509_new()) == NULL) goto end;
82555714Skris
82655714Skris			/* Set version to V3 */
82755714Skris			if(!X509_set_version(x509ss, 2)) goto end;
828109998Smarkm			if (serial)
829109998Smarkm				{
830109998Smarkm				if (!X509_set_serialNumber(x509ss, serial)) goto end;
831109998Smarkm				}
832109998Smarkm			else
833109998Smarkm				{
834109998Smarkm				if (!ASN1_INTEGER_set(X509_get_serialNumber(x509ss),0L)) goto end;
835109998Smarkm				}
83655714Skris
837100928Snectar			if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) goto end;
838100928Snectar			if (!X509_gmtime_adj(X509_get_notBefore(x509ss),0)) goto end;
839100928Snectar			if (!X509_gmtime_adj(X509_get_notAfter(x509ss), (long)60*60*24*days)) goto end;
840100928Snectar			if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req))) goto end;
84155714Skris			tmppkey = X509_REQ_get_pubkey(req);
842100928Snectar			if (!tmppkey || !X509_set_pubkey(x509ss,tmppkey)) goto end;
84355714Skris			EVP_PKEY_free(tmppkey);
84455714Skris
84555714Skris			/* Set up V3 context struct */
84655714Skris
84755714Skris			X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0);
848109998Smarkm			X509V3_set_nconf(&ext_ctx, req_conf);
84955714Skris
85055714Skris			/* Add extensions */
851109998Smarkm			if(extensions && !X509V3_EXT_add_nconf(req_conf,
85255714Skris				 	&ext_ctx, extensions, x509ss))
853109998Smarkm				{
854109998Smarkm				BIO_printf(bio_err,
855109998Smarkm					"Error Loading extension section %s\n",
856109998Smarkm					extensions);
857109998Smarkm				goto end;
858109998Smarkm				}
859109998Smarkm
86055714Skris			if (!(i=X509_sign(x509ss,pkey,digest)))
86155714Skris				goto end;
86255714Skris			}
86355714Skris		else
86455714Skris			{
86559191Skris			X509V3_CTX ext_ctx;
86659191Skris
86759191Skris			/* Set up V3 context struct */
86859191Skris
86959191Skris			X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0);
870109998Smarkm			X509V3_set_nconf(&ext_ctx, req_conf);
87159191Skris
87259191Skris			/* Add extensions */
873109998Smarkm			if(req_exts && !X509V3_EXT_REQ_add_nconf(req_conf,
87459191Skris				 	&ext_ctx, req_exts, req))
875109998Smarkm				{
876109998Smarkm				BIO_printf(bio_err,
877109998Smarkm					"Error Loading extension section %s\n",
878109998Smarkm					req_exts);
879109998Smarkm				goto end;
880109998Smarkm				}
88155714Skris			if (!(i=X509_REQ_sign(req,pkey,digest)))
88255714Skris				goto end;
88355714Skris			}
88455714Skris		}
88555714Skris
886109998Smarkm	if (subj && x509)
887109998Smarkm		{
888109998Smarkm		BIO_printf(bio_err, "Cannot modifiy certificate subject\n");
889109998Smarkm		goto end;
890109998Smarkm		}
891109998Smarkm
892109998Smarkm	if (subj && !x509)
893109998Smarkm		{
894109998Smarkm		if (verbose)
895109998Smarkm			{
896109998Smarkm			BIO_printf(bio_err, "Modifying Request's Subject\n");
897109998Smarkm			print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), nmflag);
898109998Smarkm			}
899109998Smarkm
900109998Smarkm		if (build_subject(req, subj, chtype) == 0)
901109998Smarkm			{
902109998Smarkm			BIO_printf(bio_err, "ERROR: cannot modify subject\n");
903109998Smarkm			ex=1;
904109998Smarkm			goto end;
905109998Smarkm			}
906109998Smarkm
907109998Smarkm		req->req_info->enc.modified = 1;
908109998Smarkm
909109998Smarkm		if (verbose)
910109998Smarkm			{
911109998Smarkm			print_name(bio_err, "new subject=", X509_REQ_get_subject_name(req), nmflag);
912109998Smarkm			}
913109998Smarkm		}
914109998Smarkm
91555714Skris	if (verify && !x509)
91655714Skris		{
91755714Skris		int tmp=0;
91855714Skris
91955714Skris		if (pkey == NULL)
92055714Skris			{
92155714Skris			pkey=X509_REQ_get_pubkey(req);
92255714Skris			tmp=1;
92355714Skris			if (pkey == NULL) goto end;
92455714Skris			}
92555714Skris
92655714Skris		i=X509_REQ_verify(req,pkey);
92755714Skris		if (tmp) {
92855714Skris			EVP_PKEY_free(pkey);
92955714Skris			pkey=NULL;
93055714Skris		}
93155714Skris
93255714Skris		if (i < 0)
93355714Skris			{
93455714Skris			goto end;
93555714Skris			}
93655714Skris		else if (i == 0)
93755714Skris			{
93855714Skris			BIO_printf(bio_err,"verify failure\n");
939109998Smarkm			ERR_print_errors(bio_err);
94055714Skris			}
94155714Skris		else /* if (i > 0) */
94255714Skris			BIO_printf(bio_err,"verify OK\n");
94355714Skris		}
94455714Skris
945109998Smarkm	if (noout && !text && !modulus && !subject && !pubkey)
94655714Skris		{
94755714Skris		ex=0;
94855714Skris		goto end;
94955714Skris		}
95055714Skris
95155714Skris	if (outfile == NULL)
95268651Skris		{
95355714Skris		BIO_set_fp(out,stdout,BIO_NOCLOSE);
954109998Smarkm#ifdef OPENSSL_SYS_VMS
95568651Skris		{
95668651Skris		BIO *tmpbio = BIO_new(BIO_f_linebuffer());
95768651Skris		out = BIO_push(tmpbio, out);
95868651Skris		}
95968651Skris#endif
96068651Skris		}
96155714Skris	else
96255714Skris		{
96355714Skris		if ((keyout != NULL) && (strcmp(outfile,keyout) == 0))
96455714Skris			i=(int)BIO_append_filename(out,outfile);
96555714Skris		else
96655714Skris			i=(int)BIO_write_filename(out,outfile);
96755714Skris		if (!i)
96855714Skris			{
96955714Skris			perror(outfile);
97055714Skris			goto end;
97155714Skris			}
97255714Skris		}
97355714Skris
974109998Smarkm	if (pubkey)
975109998Smarkm		{
976109998Smarkm		EVP_PKEY *tpubkey;
977109998Smarkm		tpubkey=X509_REQ_get_pubkey(req);
978109998Smarkm		if (tpubkey == NULL)
979109998Smarkm			{
980109998Smarkm			BIO_printf(bio_err,"Error getting public key\n");
981109998Smarkm			ERR_print_errors(bio_err);
982109998Smarkm			goto end;
983109998Smarkm			}
984109998Smarkm		PEM_write_bio_PUBKEY(out, tpubkey);
985109998Smarkm		EVP_PKEY_free(tpubkey);
986109998Smarkm		}
987109998Smarkm
98855714Skris	if (text)
98955714Skris		{
99055714Skris		if (x509)
991109998Smarkm			X509_print_ex(out, x509ss, nmflag, reqflag);
99255714Skris		else
993109998Smarkm			X509_REQ_print_ex(out, req, nmflag, reqflag);
99455714Skris		}
99555714Skris
996109998Smarkm	if(subject)
997109998Smarkm		{
998109998Smarkm		if(x509)
999109998Smarkm			print_name(out, "subject=", X509_get_subject_name(x509ss), nmflag);
1000109998Smarkm		else
1001109998Smarkm			print_name(out, "subject=", X509_REQ_get_subject_name(req), nmflag);
1002109998Smarkm		}
1003109998Smarkm
100455714Skris	if (modulus)
100555714Skris		{
1006109998Smarkm		EVP_PKEY *tpubkey;
100755714Skris
100855714Skris		if (x509)
1009109998Smarkm			tpubkey=X509_get_pubkey(x509ss);
101055714Skris		else
1011109998Smarkm			tpubkey=X509_REQ_get_pubkey(req);
1012109998Smarkm		if (tpubkey == NULL)
101355714Skris			{
101455714Skris			fprintf(stdout,"Modulus=unavailable\n");
101555714Skris			goto end;
101655714Skris			}
101755714Skris		fprintf(stdout,"Modulus=");
1018109998Smarkm#ifndef OPENSSL_NO_RSA
1019109998Smarkm		if (tpubkey->type == EVP_PKEY_RSA)
1020109998Smarkm			BN_print(out,tpubkey->pkey.rsa->n);
102155714Skris		else
102255714Skris#endif
102355714Skris			fprintf(stdout,"Wrong Algorithm type");
1024109998Smarkm		EVP_PKEY_free(tpubkey);
102555714Skris		fprintf(stdout,"\n");
102655714Skris		}
102755714Skris
102855714Skris	if (!noout && !x509)
102955714Skris		{
103055714Skris		if 	(outformat == FORMAT_ASN1)
103155714Skris			i=i2d_X509_REQ_bio(out,req);
103259191Skris		else if (outformat == FORMAT_PEM) {
103359191Skris			if(newhdr) i=PEM_write_bio_X509_REQ_NEW(out,req);
103459191Skris			else i=PEM_write_bio_X509_REQ(out,req);
103559191Skris		} else {
103655714Skris			BIO_printf(bio_err,"bad output format specified for outfile\n");
103755714Skris			goto end;
103855714Skris			}
103955714Skris		if (!i)
104055714Skris			{
104155714Skris			BIO_printf(bio_err,"unable to write X509 request\n");
104255714Skris			goto end;
104355714Skris			}
104455714Skris		}
104555714Skris	if (!noout && x509 && (x509ss != NULL))
104655714Skris		{
104755714Skris		if 	(outformat == FORMAT_ASN1)
104855714Skris			i=i2d_X509_bio(out,x509ss);
104955714Skris		else if (outformat == FORMAT_PEM)
105055714Skris			i=PEM_write_bio_X509(out,x509ss);
105155714Skris		else	{
105255714Skris			BIO_printf(bio_err,"bad output format specified for outfile\n");
105355714Skris			goto end;
105455714Skris			}
105555714Skris		if (!i)
105655714Skris			{
105755714Skris			BIO_printf(bio_err,"unable to write X509 certificate\n");
105855714Skris			goto end;
105955714Skris			}
106055714Skris		}
106155714Skris	ex=0;
106255714Skrisend:
1063109998Smarkm#ifndef MONOLITH
1064109998Smarkm	if(to_free)
1065109998Smarkm		OPENSSL_free(to_free);
1066109998Smarkm#endif
106755714Skris	if (ex)
106855714Skris		{
106955714Skris		ERR_print_errors(bio_err);
107055714Skris		}
1071109998Smarkm	if ((req_conf != NULL) && (req_conf != config)) NCONF_free(req_conf);
107255714Skris	BIO_free(in);
107368651Skris	BIO_free_all(out);
107455714Skris	EVP_PKEY_free(pkey);
107555714Skris	X509_REQ_free(req);
107655714Skris	X509_free(x509ss);
1077109998Smarkm	ASN1_INTEGER_free(serial);
107868651Skris	if(passargin && passin) OPENSSL_free(passin);
107968651Skris	if(passargout && passout) OPENSSL_free(passout);
108055714Skris	OBJ_cleanup();
1081109998Smarkm#ifndef OPENSSL_NO_DSA
108255714Skris	if (dsa_params != NULL) DSA_free(dsa_params);
108355714Skris#endif
1084109998Smarkm	apps_shutdown();
1085109998Smarkm	OPENSSL_EXIT(ex);
108655714Skris	}
108755714Skris
1088109998Smarkmstatic int make_REQ(X509_REQ *req, EVP_PKEY *pkey, char *subj, int attribs,
1089109998Smarkm			unsigned long chtype)
109055714Skris	{
109155714Skris	int ret=0,i;
109259191Skris	char no_prompt = 0;
109359191Skris	STACK_OF(CONF_VALUE) *dn_sk, *attr_sk = NULL;
109459191Skris	char *tmp, *dn_sect,*attr_sect;
109559191Skris
1096109998Smarkm	tmp=NCONF_get_string(req_conf,SECTION,PROMPT);
1097109998Smarkm	if (tmp == NULL)
1098109998Smarkm		ERR_clear_error();
109959191Skris	if((tmp != NULL) && !strcmp(tmp, "no")) no_prompt = 1;
110059191Skris
1101109998Smarkm	dn_sect=NCONF_get_string(req_conf,SECTION,DISTINGUISHED_NAME);
110259191Skris	if (dn_sect == NULL)
110355714Skris		{
110455714Skris		BIO_printf(bio_err,"unable to find '%s' in config\n",
110555714Skris			DISTINGUISHED_NAME);
110655714Skris		goto err;
110755714Skris		}
1108109998Smarkm	dn_sk=NCONF_get_section(req_conf,dn_sect);
110959191Skris	if (dn_sk == NULL)
111055714Skris		{
111159191Skris		BIO_printf(bio_err,"unable to get '%s' section\n",dn_sect);
111255714Skris		goto err;
111355714Skris		}
111455714Skris
1115109998Smarkm	attr_sect=NCONF_get_string(req_conf,SECTION,ATTRIBUTES);
111659191Skris	if (attr_sect == NULL)
1117109998Smarkm		{
1118109998Smarkm		ERR_clear_error();
111959191Skris		attr_sk=NULL;
1120109998Smarkm		}
112155714Skris	else
112255714Skris		{
1123109998Smarkm		attr_sk=NCONF_get_section(req_conf,attr_sect);
112459191Skris		if (attr_sk == NULL)
112555714Skris			{
112659191Skris			BIO_printf(bio_err,"unable to get '%s' section\n",attr_sect);
112755714Skris			goto err;
112855714Skris			}
112955714Skris		}
113055714Skris
113159191Skris	/* setup version number */
113259191Skris	if (!X509_REQ_set_version(req,0L)) goto err; /* version 1 */
113355714Skris
1134109998Smarkm	if (no_prompt)
1135109998Smarkm		i = auto_info(req, dn_sk, attr_sk, attribs, chtype);
1136109998Smarkm	else
1137109998Smarkm		{
1138109998Smarkm		if (subj)
1139109998Smarkm			i = build_subject(req, subj, chtype);
1140109998Smarkm		else
1141109998Smarkm			i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype);
1142109998Smarkm		}
114359191Skris	if(!i) goto err;
114459191Skris
1145100928Snectar	if (!X509_REQ_set_pubkey(req,pkey)) goto err;
114659191Skris
114759191Skris	ret=1;
114859191Skriserr:
114959191Skris	return(ret);
115059191Skris	}
115159191Skris
1152109998Smarkm/*
1153109998Smarkm * subject is expected to be in the format /type0=value0/type1=value1/type2=...
1154109998Smarkm * where characters may be escaped by \
1155109998Smarkm */
1156109998Smarkmstatic int build_subject(X509_REQ *req, char *subject, unsigned long chtype)
1157109998Smarkm	{
1158109998Smarkm	X509_NAME *n;
115959191Skris
1160109998Smarkm	if (!(n = do_subject(subject, chtype)))
1161109998Smarkm		return 0;
1162109998Smarkm
1163109998Smarkm	if (!X509_REQ_set_subject_name(req, n))
1164109998Smarkm		{
1165109998Smarkm		X509_NAME_free(n);
1166109998Smarkm		return 0;
1167109998Smarkm		}
1168109998Smarkm	X509_NAME_free(n);
1169109998Smarkm	return 1;
1170109998Smarkm}
1171109998Smarkm
1172109998Smarkm
117359191Skrisstatic int prompt_info(X509_REQ *req,
117459191Skris		STACK_OF(CONF_VALUE) *dn_sk, char *dn_sect,
1175109998Smarkm		STACK_OF(CONF_VALUE) *attr_sk, char *attr_sect, int attribs,
1176109998Smarkm		unsigned long chtype)
117759191Skris	{
117859191Skris	int i;
117959191Skris	char *p,*q;
118059191Skris	char buf[100];
1181109998Smarkm	int nid;
1182109998Smarkm	long n_min,n_max;
118359191Skris	char *type,*def,*value;
118459191Skris	CONF_VALUE *v;
118559191Skris	X509_NAME *subj;
118659191Skris	subj = X509_REQ_get_subject_name(req);
118755714Skris
1188109998Smarkm	if(!batch)
1189109998Smarkm		{
1190109998Smarkm		BIO_printf(bio_err,"You are about to be asked to enter information that will be incorporated\n");
1191109998Smarkm		BIO_printf(bio_err,"into your certificate request.\n");
1192109998Smarkm		BIO_printf(bio_err,"What you are about to enter is what is called a Distinguished Name or a DN.\n");
1193109998Smarkm		BIO_printf(bio_err,"There are quite a few fields but you can leave some blank\n");
1194109998Smarkm		BIO_printf(bio_err,"For some fields there will be a default value,\n");
1195109998Smarkm		BIO_printf(bio_err,"If you enter '.', the field will be left blank.\n");
1196109998Smarkm		BIO_printf(bio_err,"-----\n");
1197109998Smarkm		}
119855714Skris
1199109998Smarkm
120059191Skris	if (sk_CONF_VALUE_num(dn_sk))
120155714Skris		{
120255714Skris		i= -1;
120355714Skrisstart:		for (;;)
120455714Skris			{
120555714Skris			i++;
120659191Skris			if (sk_CONF_VALUE_num(dn_sk) <= i) break;
120755714Skris
120859191Skris			v=sk_CONF_VALUE_value(dn_sk,i);
120955714Skris			p=q=NULL;
121055714Skris			type=v->name;
121155714Skris			if(!check_end(type,"_min") || !check_end(type,"_max") ||
121255714Skris				!check_end(type,"_default") ||
121355714Skris					 !check_end(type,"_value")) continue;
121455714Skris			/* Skip past any leading X. X: X, etc to allow for
121555714Skris			 * multiple instances
121655714Skris			 */
121755714Skris			for(p = v->name; *p ; p++)
121855714Skris				if ((*p == ':') || (*p == ',') ||
121955714Skris							 (*p == '.')) {
122055714Skris					p++;
122155714Skris					if(*p) type = p;
122255714Skris					break;
122355714Skris				}
122455714Skris			/* If OBJ not recognised ignore it */
122555714Skris			if ((nid=OBJ_txt2nid(type)) == NID_undef) goto start;
1226109998Smarkm
1227109998Smarkm			if(strlen(v->name) > sizeof buf-9)
1228109998Smarkm			   {
1229109998Smarkm			   BIO_printf(bio_err,"Name '%s' too long\n",v->name);
1230109998Smarkm			   return 0;
1231109998Smarkm			   }
1232109998Smarkm
123355714Skris			sprintf(buf,"%s_default",v->name);
1234109998Smarkm			if ((def=NCONF_get_string(req_conf,dn_sect,buf)) == NULL)
1235109998Smarkm				{
1236109998Smarkm				ERR_clear_error();
123755714Skris				def="";
1238109998Smarkm				}
123955714Skris			sprintf(buf,"%s_value",v->name);
1240109998Smarkm			if ((value=NCONF_get_string(req_conf,dn_sect,buf)) == NULL)
1241109998Smarkm				{
1242109998Smarkm				ERR_clear_error();
124355714Skris				value=NULL;
1244109998Smarkm				}
124555714Skris
124655714Skris			sprintf(buf,"%s_min",v->name);
1247109998Smarkm			if (!NCONF_get_number(req_conf,dn_sect,buf, &n_min))
1248111147Snectar				{
1249111147Snectar				ERR_clear_error();
1250109998Smarkm				n_min = -1;
1251111147Snectar				}
125255714Skris
125355714Skris			sprintf(buf,"%s_max",v->name);
1254109998Smarkm			if (!NCONF_get_number(req_conf,dn_sect,buf, &n_max))
1255111147Snectar				{
1256111147Snectar				ERR_clear_error();
1257109998Smarkm				n_max = -1;
1258111147Snectar				}
125955714Skris
126059191Skris			if (!add_DN_object(subj,v->value,def,value,nid,
1261109998Smarkm				n_min,n_max, chtype))
126259191Skris				return 0;
126355714Skris			}
126459191Skris		if (X509_NAME_entry_count(subj) == 0)
126555714Skris			{
126655714Skris			BIO_printf(bio_err,"error, no objects specified in config file\n");
126759191Skris			return 0;
126855714Skris			}
126955714Skris
127055714Skris		if (attribs)
127155714Skris			{
1272109998Smarkm			if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) && (!batch))
127355714Skris				{
127455714Skris				BIO_printf(bio_err,"\nPlease enter the following 'extra' attributes\n");
127555714Skris				BIO_printf(bio_err,"to be sent with your certificate request\n");
127655714Skris				}
127755714Skris
127855714Skris			i= -1;
127955714Skrisstart2:			for (;;)
128055714Skris				{
128155714Skris				i++;
128259191Skris				if ((attr_sk == NULL) ||
128359191Skris					    (sk_CONF_VALUE_num(attr_sk) <= i))
128455714Skris					break;
128555714Skris
128659191Skris				v=sk_CONF_VALUE_value(attr_sk,i);
128755714Skris				type=v->name;
128855714Skris				if ((nid=OBJ_txt2nid(type)) == NID_undef)
128955714Skris					goto start2;
129055714Skris
1291109998Smarkm				if(strlen(v->name) > sizeof buf-9)
1292109998Smarkm				   {
1293109998Smarkm				   BIO_printf(bio_err,"Name '%s' too long\n",v->name);
1294109998Smarkm				   return 0;
1295109998Smarkm				   }
1296109998Smarkm
129755714Skris				sprintf(buf,"%s_default",type);
1298109998Smarkm				if ((def=NCONF_get_string(req_conf,attr_sect,buf))
129955714Skris					== NULL)
1300109998Smarkm					{
1301109998Smarkm					ERR_clear_error();
130255714Skris					def="";
1303109998Smarkm					}
130455714Skris
1305109998Smarkm
130655714Skris				sprintf(buf,"%s_value",type);
1307109998Smarkm				if ((value=NCONF_get_string(req_conf,attr_sect,buf))
130855714Skris					== NULL)
1309109998Smarkm					{
1310109998Smarkm					ERR_clear_error();
131155714Skris					value=NULL;
1312109998Smarkm					}
131355714Skris
131455714Skris				sprintf(buf,"%s_min",type);
1315109998Smarkm				if (!NCONF_get_number(req_conf,attr_sect,buf, &n_min))
1316109998Smarkm					n_min = -1;
131755714Skris
131855714Skris				sprintf(buf,"%s_max",type);
1319109998Smarkm				if (!NCONF_get_number(req_conf,attr_sect,buf, &n_max))
1320109998Smarkm					n_max = -1;
132155714Skris
132259191Skris				if (!add_attribute_object(req,
1323109998Smarkm					v->value,def,value,nid,n_min,n_max, chtype))
132459191Skris					return 0;
132555714Skris				}
132655714Skris			}
132755714Skris		}
132855714Skris	else
132955714Skris		{
133055714Skris		BIO_printf(bio_err,"No template, please set one up.\n");
133159191Skris		return 0;
133255714Skris		}
133355714Skris
133459191Skris	return 1;
133555714Skris
133655714Skris	}
133755714Skris
133859191Skrisstatic int auto_info(X509_REQ *req, STACK_OF(CONF_VALUE) *dn_sk,
1339109998Smarkm			STACK_OF(CONF_VALUE) *attr_sk, int attribs, unsigned long chtype)
134059191Skris	{
134159191Skris	int i;
134259191Skris	char *p,*q;
134359191Skris	char *type;
134459191Skris	CONF_VALUE *v;
134559191Skris	X509_NAME *subj;
134659191Skris
134759191Skris	subj = X509_REQ_get_subject_name(req);
134859191Skris
134959191Skris	for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++)
135059191Skris		{
135159191Skris		v=sk_CONF_VALUE_value(dn_sk,i);
135259191Skris		p=q=NULL;
135359191Skris		type=v->name;
135459191Skris		/* Skip past any leading X. X: X, etc to allow for
135559191Skris		 * multiple instances
135659191Skris		 */
135759191Skris		for(p = v->name; *p ; p++)
135868651Skris#ifndef CHARSET_EBCDIC
135959191Skris			if ((*p == ':') || (*p == ',') || (*p == '.')) {
136068651Skris#else
136168651Skris			if ((*p == os_toascii[':']) || (*p == os_toascii[',']) || (*p == os_toascii['.'])) {
136268651Skris#endif
136359191Skris				p++;
136459191Skris				if(*p) type = p;
136559191Skris				break;
136659191Skris			}
1367109998Smarkm		if (!X509_NAME_add_entry_by_txt(subj,type, chtype,
136859191Skris				(unsigned char *) v->value,-1,-1,0)) return 0;
136959191Skris
137059191Skris		}
137159191Skris
137259191Skris		if (!X509_NAME_entry_count(subj))
137359191Skris			{
137459191Skris			BIO_printf(bio_err,"error, no objects specified in config file\n");
137559191Skris			return 0;
137659191Skris			}
137759191Skris		if (attribs)
137859191Skris			{
137959191Skris			for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++)
138059191Skris				{
138159191Skris				v=sk_CONF_VALUE_value(attr_sk,i);
1382109998Smarkm				if(!X509_REQ_add1_attr_by_txt(req, v->name, chtype,
138359191Skris					(unsigned char *)v->value, -1)) return 0;
138459191Skris				}
138559191Skris			}
138659191Skris	return 1;
138759191Skris	}
138859191Skris
138959191Skris
139055714Skrisstatic int add_DN_object(X509_NAME *n, char *text, char *def, char *value,
1391109998Smarkm	     int nid, int n_min, int n_max, unsigned long chtype)
139255714Skris	{
139359191Skris	int i,ret=0;
139455714Skris	MS_STATIC char buf[1024];
139559191Skrisstart:
1396109998Smarkm	if (!batch) BIO_printf(bio_err,"%s [%s]:",text,def);
139755714Skris	(void)BIO_flush(bio_err);
1398109998Smarkm	if(value != NULL)
139955714Skris		{
1400109998Smarkm		OPENSSL_assert(strlen(value) < sizeof buf-2);
140155714Skris		strcpy(buf,value);
140255714Skris		strcat(buf,"\n");
140355714Skris		BIO_printf(bio_err,"%s\n",value);
140455714Skris		}
140555714Skris	else
140655714Skris		{
140755714Skris		buf[0]='\0';
1408109998Smarkm		if (!batch)
1409109998Smarkm			{
1410109998Smarkm			fgets(buf,sizeof buf,stdin);
1411109998Smarkm			}
1412109998Smarkm		else
1413109998Smarkm			{
1414109998Smarkm			buf[0] = '\n';
1415109998Smarkm			buf[1] = '\0';
1416109998Smarkm			}
141755714Skris		}
141855714Skris
141955714Skris	if (buf[0] == '\0') return(0);
142055714Skris	else if (buf[0] == '\n')
142155714Skris		{
142255714Skris		if ((def == NULL) || (def[0] == '\0'))
142355714Skris			return(1);
142455714Skris		strcpy(buf,def);
142555714Skris		strcat(buf,"\n");
142655714Skris		}
142755714Skris	else if ((buf[0] == '.') && (buf[1] == '\n')) return(1);
142855714Skris
142955714Skris	i=strlen(buf);
143055714Skris	if (buf[i-1] != '\n')
143155714Skris		{
143255714Skris		BIO_printf(bio_err,"weird input :-(\n");
143355714Skris		return(0);
143455714Skris		}
143555714Skris	buf[--i]='\0';
143655714Skris#ifdef CHARSET_EBCDIC
143755714Skris	ebcdic2ascii(buf, buf, i);
143855714Skris#endif
1439109998Smarkm	if(!req_check_len(i, n_min, n_max)) goto start;
1440109998Smarkm	if (!X509_NAME_add_entry_by_NID(n,nid, chtype,
144159191Skris				(unsigned char *) buf, -1,-1,0)) goto err;
144255714Skris	ret=1;
144355714Skriserr:
144455714Skris	return(ret);
144555714Skris	}
144655714Skris
144759191Skrisstatic int add_attribute_object(X509_REQ *req, char *text,
1448109998Smarkm				char *def, char *value, int nid, int n_min,
1449109998Smarkm				int n_max, unsigned long chtype)
145055714Skris	{
145159191Skris	int i;
145255714Skris	static char buf[1024];
145355714Skris
145455714Skrisstart:
1455109998Smarkm	if (!batch) BIO_printf(bio_err,"%s [%s]:",text,def);
145655714Skris	(void)BIO_flush(bio_err);
145755714Skris	if (value != NULL)
145855714Skris		{
1459109998Smarkm		OPENSSL_assert(strlen(value) < sizeof buf-2);
146055714Skris		strcpy(buf,value);
146155714Skris		strcat(buf,"\n");
146255714Skris		BIO_printf(bio_err,"%s\n",value);
146355714Skris		}
146455714Skris	else
146555714Skris		{
146655714Skris		buf[0]='\0';
1467109998Smarkm		if (!batch)
1468109998Smarkm			{
1469109998Smarkm			fgets(buf,sizeof buf,stdin);
1470109998Smarkm			}
1471109998Smarkm		else
1472109998Smarkm			{
1473109998Smarkm			buf[0] = '\n';
1474109998Smarkm			buf[1] = '\0';
1475109998Smarkm			}
147655714Skris		}
147755714Skris
147855714Skris	if (buf[0] == '\0') return(0);
147955714Skris	else if (buf[0] == '\n')
148055714Skris		{
148155714Skris		if ((def == NULL) || (def[0] == '\0'))
148255714Skris			return(1);
148355714Skris		strcpy(buf,def);
148455714Skris		strcat(buf,"\n");
148555714Skris		}
148655714Skris	else if ((buf[0] == '.') && (buf[1] == '\n')) return(1);
148755714Skris
148855714Skris	i=strlen(buf);
148955714Skris	if (buf[i-1] != '\n')
149055714Skris		{
149155714Skris		BIO_printf(bio_err,"weird input :-(\n");
149255714Skris		return(0);
149355714Skris		}
149455714Skris	buf[--i]='\0';
149568651Skris#ifdef CHARSET_EBCDIC
149668651Skris	ebcdic2ascii(buf, buf, i);
149768651Skris#endif
1498109998Smarkm	if(!req_check_len(i, n_min, n_max)) goto start;
149955714Skris
1500109998Smarkm	if(!X509_REQ_add1_attr_by_NID(req, nid, chtype,
150159191Skris					(unsigned char *)buf, -1)) {
150259191Skris		BIO_printf(bio_err, "Error adding attribute\n");
150359191Skris		ERR_print_errors(bio_err);
150455714Skris		goto err;
150559191Skris	}
150655714Skris
150755714Skris	return(1);
150855714Skriserr:
150955714Skris	return(0);
151055714Skris	}
151155714Skris
1512109998Smarkm#ifndef OPENSSL_NO_RSA
151355714Skrisstatic void MS_CALLBACK req_cb(int p, int n, void *arg)
151455714Skris	{
151555714Skris	char c='*';
151655714Skris
151755714Skris	if (p == 0) c='.';
151855714Skris	if (p == 1) c='+';
151955714Skris	if (p == 2) c='*';
152055714Skris	if (p == 3) c='\n';
152155714Skris	BIO_write((BIO *)arg,&c,1);
152255714Skris	(void)BIO_flush((BIO *)arg);
152355714Skris#ifdef LINT
152455714Skris	p=n;
152555714Skris#endif
152655714Skris	}
152759191Skris#endif
152855714Skris
1529109998Smarkmstatic int req_check_len(int len, int n_min, int n_max)
153055714Skris	{
1531109998Smarkm	if ((n_min > 0) && (len < n_min))
153255714Skris		{
1533109998Smarkm		BIO_printf(bio_err,"string is too short, it needs to be at least %d bytes long\n",n_min);
153455714Skris		return(0);
153555714Skris		}
1536109998Smarkm	if ((n_max >= 0) && (len > n_max))
153755714Skris		{
1538109998Smarkm		BIO_printf(bio_err,"string is too long, it needs to be less than  %d bytes long\n",n_max);
153955714Skris		return(0);
154055714Skris		}
154155714Skris	return(1);
154255714Skris	}
154355714Skris
154455714Skris/* Check if the end of a string matches 'end' */
154555714Skrisstatic int check_end(char *str, char *end)
154655714Skris{
154755714Skris	int elen, slen;
154855714Skris	char *tmp;
154955714Skris	elen = strlen(end);
155055714Skris	slen = strlen(str);
155155714Skris	if(elen > slen) return 1;
155255714Skris	tmp = str + slen - elen;
155355714Skris	return strcmp(tmp, end);
155455714Skris}
1555