Fix typo in i2d_ASN1_ENUMERATED

Fix bug in read only memory BIOs so BIO_reset() works.

Add sign and verify options to dgst utility, need
to update docs.
diff --git a/CHANGES b/CHANGES
index e0120ae..9c3a1e3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,13 +4,17 @@
 
  Changes between 0.9.5a and 0.9.6  [xx XXX 2000]
 
+  *) New options added to the 'dgst' utility for signature
+     generation and verification.
+     [Steve Henson]
+
   *) Unrecognized PKCS#7 content types are now handled via a
      catch all ASN1_TYPE structure. This allows unsupported
      types to be stored as a "blob" and an application can
      encode and decode it manually.
      [Steve Henson]
 
-  *) Fix various signed/unsigned issues to make a_strex,c
+  *) Fix various signed/unsigned issues to make a_strex.c
      compile under VC++.
      [Oscar Jacobsson <oscar.jacobsson@celocom.com>]
 
diff --git a/apps/dgst.c b/apps/dgst.c
index 5286dd0..a151fb8 100644
--- a/apps/dgst.c
+++ b/apps/dgst.c
@@ -73,7 +73,8 @@
 #undef PROG
 #define PROG	dgst_main
 
-void do_fp(unsigned char *buf,BIO *f,int sep);
+void do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, char binout,
+		EVP_PKEY *key, unsigned char *sigin, unsigned int siglen);
 
 int MAIN(int, char **);
 
@@ -84,11 +85,18 @@
 	const EVP_MD *md=NULL,*m;
 	BIO *in=NULL,*inp;
 	BIO *bmd=NULL;
+	BIO *out = NULL;
 	const char *name;
 #define PROG_NAME_SIZE  16
 	char pname[PROG_NAME_SIZE];
 	int separator=0;
 	int debug=0;
+	const char *outfile = NULL, *keyfile = NULL;
+	const char *sigfile = NULL, *randfile = NULL;
+	char out_bin = -1, want_pub = 0, do_verify = 0;
+	EVP_PKEY *sigkey = NULL;
+	unsigned char *sigbuf = NULL;
+	unsigned int siglen = 0;
 
 	apps_startup();
 
@@ -113,6 +121,43 @@
 		if ((*argv)[0] != '-') break;
 		if (strcmp(*argv,"-c") == 0)
 			separator=1;
+		else if (strcmp(*argv,"-rand") == 0)
+			{
+			if (--argc < 1) break;
+			randfile=*(++argv);
+			}
+		else if (strcmp(*argv,"-out") == 0)
+			{
+			if (--argc < 1) break;
+			outfile=*(++argv);
+			}
+		else if (strcmp(*argv,"-sign") == 0)
+			{
+			if (--argc < 1) break;
+			keyfile=*(++argv);
+			}
+		else if (strcmp(*argv,"-verify") == 0)
+			{
+			if (--argc < 1) break;
+			keyfile=*(++argv);
+			want_pub = 1;
+			do_verify = 1;
+			}
+		else if (strcmp(*argv,"-prverify") == 0)
+			{
+			if (--argc < 1) break;
+			keyfile=*(++argv);
+			do_verify = 1;
+			}
+		else if (strcmp(*argv,"-signature") == 0)
+			{
+			if (--argc < 1) break;
+			sigfile=*(++argv);
+			}
+		else if (strcmp(*argv,"-hex") == 0)
+			out_bin = 0;
+		else if (strcmp(*argv,"-binary") == 0)
+			out_bin = 1;
 		else if (strcmp(*argv,"-d") == 0)
 			debug=1;
 		else if ((m=EVP_get_digestbyname(&((*argv)[1]))) != NULL)
@@ -126,12 +171,26 @@
 	if (md == NULL)
 		md=EVP_md5();
 
+	if(do_verify && !sigfile) {
+		BIO_printf(bio_err, "No signature to verify: use the -signature option\n");
+		err = 1; 
+		goto end;
+	}
+
 	if ((argc > 0) && (argv[0][0] == '-')) /* bad option */
 		{
 		BIO_printf(bio_err,"unknown option '%s'\n",*argv);
 		BIO_printf(bio_err,"options are\n");
-		BIO_printf(bio_err,"-c   to output the digest with separating colons\n");
-		BIO_printf(bio_err,"-d   to output debug info\n");
+		BIO_printf(bio_err,"-c              to output the digest with separating colons\n");
+		BIO_printf(bio_err,"-d              to output debug info\n");
+		BIO_printf(bio_err,"-hex            output as hex dump\n");
+		BIO_printf(bio_err,"-binary         output in binary form\n");
+		BIO_printf(bio_err,"-sign   file    sign digest using private key in file\n");
+		BIO_printf(bio_err,"-verify file    verify a signature using public key in file\n");
+		BIO_printf(bio_err,"-prverify file  verify a signature using private key in file\n");
+		BIO_printf(bio_err,"-signature file signature to verify\n");
+		BIO_printf(bio_err,"-binary         output in binary form\n");
+
 		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm (default)\n",
 			LN_md5,LN_md5);
 		BIO_printf(bio_err,"-%3s to use the %s message digest algorithm\n",
@@ -149,7 +208,7 @@
 		err=1;
 		goto end;
 		}
-	
+
 	in=BIO_new(BIO_s_file());
 	bmd=BIO_new(BIO_f_md());
 	if (debug)
@@ -165,6 +224,72 @@
 		goto end;
 		}
 
+	if(out_bin == -1) {
+		if(keyfile) out_bin = 1;
+		else out_bin = 0;
+	}
+
+	if(randfile)
+		app_RAND_load_file(randfile, bio_err, 0);
+
+	if(outfile) {
+		if(out_bin)
+			out = BIO_new_file(outfile, "wb");
+		else    out = BIO_new_file(outfile, "w");
+	} else out = BIO_new_fp(stdout, BIO_NOCLOSE);
+
+	if(!out) {
+		BIO_printf(bio_err, "Error opening output file %s\n", 
+					outfile ? outfile : "(stdout)");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+
+	if(keyfile) {
+		BIO *keybio;
+		keybio = BIO_new_file(keyfile, "r");
+		if(!keybio) {
+			BIO_printf(bio_err, "Error opening key file %s\n",
+								keyfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		
+		if(want_pub) 
+			sigkey = PEM_read_bio_PUBKEY(keybio, NULL, NULL, NULL);
+		else sigkey = PEM_read_bio_PrivateKey(keybio, NULL, NULL, NULL);
+		BIO_free(keybio);
+		if(!sigkey) {
+			BIO_printf(bio_err, "Error reading key file %s\n",
+								keyfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+
+	if(sigfile && sigkey) {
+		BIO *sigbio;
+		sigbio = BIO_new_file(sigfile, "rb");
+		siglen = EVP_PKEY_size(sigkey);
+		sigbuf = OPENSSL_malloc(siglen);
+		if(!sigbio) {
+			BIO_printf(bio_err, "Error opening signature file %s\n",
+								sigfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		siglen = BIO_read(sigbio, sigbuf, siglen);
+		BIO_free(sigbio);
+		if(siglen <= 0) {
+			BIO_printf(bio_err, "Error reading signature file %s\n",
+								sigfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+		
+
+
 	/* we use md as a filter, reading from 'in' */
 	BIO_set_md(bmd,md);
 	inp=BIO_push(bmd,in);
@@ -172,7 +297,7 @@
 	if (argc == 0)
 		{
 		BIO_set_fp(in,stdin,BIO_NOCLOSE);
-		do_fp(buf,inp,separator);
+		do_fp(out, buf,inp,separator, out_bin, sigkey, sigbuf, siglen);
 		}
 	else
 		{
@@ -185,8 +310,9 @@
 				err++;
 				continue;
 				}
-			printf("%s(%s)= ",name,argv[i]);
-			do_fp(buf,inp,separator);
+			if(!out_bin) BIO_printf(out, "%s(%s)= ",name,argv[i]);
+			do_fp(out, buf,inp,separator, out_bin, sigkey, 
+								sigbuf, siglen);
 			(void)BIO_reset(bmd);
 			}
 		}
@@ -197,11 +323,15 @@
 		OPENSSL_free(buf);
 		}
 	if (in != NULL) BIO_free(in);
+	BIO_free(out);
+	EVP_PKEY_free(sigkey);
+	if(sigbuf) OPENSSL_free(sigbuf);
 	if (bmd != NULL) BIO_free(bmd);
 	EXIT(err);
 	}
 
-void do_fp(unsigned char *buf, BIO *bp, int sep)
+void do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, char binout,
+			EVP_PKEY *key, unsigned char *sigin, unsigned int siglen)
 	{
 	int len;
 	int i;
@@ -211,14 +341,44 @@
 		i=BIO_read(bp,(char *)buf,BUFSIZE);
 		if (i <= 0) break;
 		}
-	len=BIO_gets(bp,(char *)buf,BUFSIZE);
-
-	for (i=0; i<len; i++)
+	if(sigin)
 		{
-		if (sep && (i != 0))
-			putc(':',stdout);
-		printf("%02x",buf[i]);
+		EVP_MD_CTX *ctx;
+		BIO_get_md_ctx(bp, &ctx);
+		i = EVP_VerifyFinal(ctx, sigin, siglen, key); 
+		if(i > 0) BIO_printf(out, "Verified OK\n");
+		else if(i == 0) BIO_printf(out, "Verification Failure\n");
+		else
+			{
+			BIO_printf(bio_err, "Error Verifying Data\n");
+			ERR_print_errors(bio_err);
+			}
+		return;
 		}
-	printf("\n");
+	if(key)
+		{
+		EVP_MD_CTX *ctx;
+		BIO_get_md_ctx(bp, &ctx);
+		if(!EVP_SignFinal(ctx, buf, (unsigned int *)&len, key)) 
+			{
+			BIO_printf(bio_err, "Error Signing Data\n");
+			ERR_print_errors(bio_err);
+			return;
+			}
+		}
+	else
+		len=BIO_gets(bp,(char *)buf,BUFSIZE);
+
+	if(binout) BIO_write(out, buf, len);
+	else 
+		{
+		for (i=0; i<len; i++)
+			{
+			if (sep && (i != 0))
+				BIO_printf(out, ":");
+			BIO_printf(out, "%02x",buf[i]);
+			}
+		BIO_printf(out, "\n");
+		}
 	}
 
diff --git a/crypto/asn1/a_enum.c b/crypto/asn1/a_enum.c
index afd8e9a..1428d1d 100644
--- a/crypto/asn1/a_enum.c
+++ b/crypto/asn1/a_enum.c
@@ -79,7 +79,7 @@
 	len = i2c_ASN1_INTEGER(a, NULL);	
 	ret=ASN1_object_size(0,len,V_ASN1_ENUMERATED);
 	if(pp) {
-		ASN1_put_object(pp,0,ret,V_ASN1_ENUMERATED,V_ASN1_UNIVERSAL);
+		ASN1_put_object(pp,0,len,V_ASN1_ENUMERATED,V_ASN1_UNIVERSAL);
 		i2c_ASN1_INTEGER(a, pp);	
 	}
 	return ret;
diff --git a/crypto/bio/bss_mem.c b/crypto/bio/bss_mem.c
index c4e5578..4fa2cf1 100644
--- a/crypto/bio/bss_mem.c
+++ b/crypto/bio/bss_mem.c
@@ -214,6 +214,7 @@
 			/* For read only case reset to the start again */
 			if(b->flags & BIO_FLAGS_MEM_RDONLY) 
 					bm->data -= bm->max - bm->length;
+					bm->length = bm->max;
 			else {
 				memset(bm->data,0,bm->max);
 				bm->length=0;