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;
}