Hi OpenSSL-Devs

I found the bug described below in OpenSSL 1.0.0b:

Short description:

When calling PEM_read_bio_PrivateKey twice with the same EVP_PKEY structure as 
an argument, the resulting private key structure contains a useless RSA
private key after the second call (i.e. d, e, and n are all 0).

Affected OpenSSL versions:

1.0.0b has been tested and is affected. Other 1.0 versions might be affected as 
well but have not been tested. 0.9.8p and earlier 0.9.8 versions are
not affected.

Test setup:

OS: Solaris 10 SPARC
Compiler: Sun Studio 12

How to reproduce:

Attached is a test program (read_pkey.c) that reads an RSA private key twice 
and prints it to stdout after every read. One would expect to see the
same output twice, but the second time, the values for d, e, and n are all 0.

Instructions on how to setup, build and run the test program can be found in 
the attached README file.

Fix:

The attached patch fixes the problem.

Please review the suggested patch and take appropriate actions for future 
releases.

Kind regards,

Stefan Birrer
-- 

 AdNovum Informatik AG
 Stefan Birrer, Software Engineer
 Dipl. Informatik-Ing. ETH

 Roentgenstrasse 22, CH-8005 Zurich
 mailto:[email protected]
 phone: +41 44 272 6111, fax: +41 44 272 6312
 http://www.adnovum.ch

 AdNovum Offices: Bern, Budapest, Singapore, Zurich (HQ)

Build OpenSSL 1.0.0b
####################

cd openssl-1.0.0b
./Configure debug-solaris-sparcv9-cc shared threads no-hw 
--openssldir=/opt/openssl
make

Generate RSA Private key 
########################

cd ../read_pkey
LD_LIBRARY_PATH=../openssl-1.0.0b ../openssl-1.0.0b/apps/openssl genrsa -out 
privkey.pem -passout "pass:password" 1024

Build test program
##################

Set variables CC and LD to your compiler and linker respectively. Set 
OPENSSL_DIR to the directory containing libcrypto.so. 

make 

Run the test program
####################

make run
OPENSSL_DIR=../openssl-1.0.0b

# Path to compiler
CC=/share/app/sun/studio/12/bin/cc
CFLAGS= -c -g -I${OPENSSL_DIR}/include

# Path to linker
LD=/share/app/sun/studio/12/bin/cc
LDFLAGS=-L${OPENSSL_DIR}

all: read_pkey

read_pkey: read_pkey.o
        ${LD} ${LDFLAGS} -o read_pkey read_pkey.o -lcrypto

read_pkey.o: read_pkey.c
        ${CC} ${CFLAGS} -o read_pkey.o read_pkey.c

run:
        LD_LIBRARY_PATH=${OPENSSL_DIR} ./read_pkey --password password 
--keyfile privkey.pem

clean:
        rm -f read_pkey *.o

#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/pem.h>

#include <errno.h>
#include <string.h>

/*----------------------------------------------------------------------------*/

BIO* out;
BIO* err;

char* program;

char* password;

/*----------------------------------------------------------------------------*/

static void print_usage();
static int password_cb(char* buf, int size, int rwflag, void* userdata);
static void print_privateKey(const EVP_PKEY* key);

/*----------------------------------------------------------------------------*/

static void print_usage() {
	BIO_printf(err, "%s --password <password> --keyfile <keyfile.pem>\n", program);

	return;
}

/*----------------------------------------------------------------------------*/

static int password_cb(char* buf, int size, int rwflag, void* userdata) {
	if (size > strlen(password) + 1) {
		strcpy(buf, password);
		return 1;
	}
	else {
		return 0;
	}
}

/*----------------------------------------------------------------------------*/

static void print_privateKey(const EVP_PKEY* key) {
	BIO_printf(out, "Private key is: \n");
	BIO_printf(out, "  e = ");
	BN_print(out, key->pkey.rsa->e);
	BIO_printf(out, "\n");
	BIO_printf(out, "  d = ");
	BN_print(out, key->pkey.rsa->d);
	BIO_printf(out, "\n");
	BIO_printf(out, "  n = ");
	BN_print(out, key->pkey.rsa->n);
	BIO_printf(out, "\n");
}

/*----------------------------------------------------------------------------*/

int main(int argc, char** argv) {

	char* keyFileName = NULL;

	BIO* keyFile = NULL;

	EVP_PKEY* key = NULL;

	int ret = -1;

	out = NULL;
	err = NULL;
	program = NULL;
	password = NULL;

	out = BIO_new(BIO_s_file());
	if (out == NULL) {
		goto err;
	}
	BIO_set_fp(out, stdout, BIO_CLOSE);

	err = BIO_new(BIO_s_file());
	if (err == NULL) {
		goto err;
	}
	BIO_set_fp(err, stderr, BIO_CLOSE);
	
	program = argv[0];
	argc--;
	argv++;
	while (argc > 0) {
		if (strcmp(argv[0], "--password") == 0) {
			if (argc == 0) {
				BIO_printf(err, "Missing argument for parameter --password\n");
				print_usage();

				goto err;
			}
			password = argv[1];
			argc--;
			argv++;
		}
		if (strcmp(argv[0], "--keyfile") == 0) {
			if (argc == 0) {
				BIO_printf(err, "Missing argument for parameter --keyfile\n");
				print_usage();

				goto err;
			}
			keyFileName = argv[1];
			argc--;
			argv++;
		}
		argc--;
		argv++;
	}

	if (password == NULL) {
		BIO_printf(err, "Missing parameter --password\n");
		print_usage();

		goto err;
	}
	if (keyFileName == NULL) {
		BIO_printf(err, "Missing parameter --keyfile\n");
		print_usage();
		
		goto err;
	}

	keyFile = BIO_new_file(keyFileName, "r");
	if (keyFile == NULL) {
		BIO_printf(err, "Failed to open key file '%s'. Reason: %s\n", keyFileName, strerror(errno));

		goto err;
	}

	if (!PEM_read_bio_PrivateKey(keyFile, &key, &password_cb, NULL)) {
		BIO_printf(err, "First read of password file '%s' failed.\n", keyFileName);

		goto err;
	}
	
	print_privateKey(key);

	BIO_reset(keyFile);

	if (!PEM_read_bio_PrivateKey(keyFile, &key, &password_cb, NULL)) {
		BIO_printf(err, "Second read of password file '%s' failed.\n", keyFileName);

		goto err;
	}

	print_privateKey(key);

	ret = 0;
err:
	if (keyFile != NULL) {
		BIO_free(keyFile);
	}

	if (err != NULL) {
		BIO_free(err);
	}

	if (out != NULL) {
		BIO_free(out);
	}

	return ret;
}
diff -crB openssl-1.0.0b/crypto/rsa/rsa_ameth.c 
openssl-1.0.0b_patched/crypto/rsa/rsa_ameth.c
*** openssl-1.0.0b/crypto/rsa/rsa_ameth.c       Wed Nov 12 04:58:05 2008
--- openssl-1.0.0b_patched/crypto/rsa/rsa_ameth.c       Tue Nov 30 11:29:34 2010
***************
*** 168,173 ****
--- 168,174 ----
  static void int_rsa_free(EVP_PKEY *pkey)
        {
        RSA_free(pkey->pkey.rsa);
+       pkey->pkey.rsa = NULL;
        }
  
  

Reply via email to