COMMAND

    OpenSSL

SYSTEMS AFFECTED

    OpenSSL up to 0.9.6a

PROBLEM

    Following  is  based   on  a  OpenSSL   Security  Advisory.    The
    pseudo-random number generator  (PRNG) in SSLeay/OpenSSL  versions
    up to 0.9.6a is  weakened by a design  error.  Knowing the  output
    of specific PRNG requests (including a number of consecutive  very
    short  PRNG  requests)  would  allow  an attacker to determine the
    PRNG's internal state and thus to predict future PRNG output.

    Typical  applications  (including  applications  using   OpenSSL's
    SSL/TLS library) are  not vulnerable to  this attack because  PRNG
    requests  usually  happen  in  larger  chunks.   It  is   strongly
    recommended upgrading  to OpenSSL  0.9.6b, which  includes a fixed
    PRNG.   If upgrading  to 0.9.6b  is not  immediately possible, the
    source code patch contained at the end of this advisory should  be
    applied.

    Recently a cryptographic flaw in OpenSSL's built-in  pseudo-random
    number generator  (PRNG) was  pointed out  to us  by Markku-Juhani
    O.  Saarinen,  who  showed  how  an attacker could reconstruct the
    PRNG's  internal  state  from  the  output  of a couple of hundred
    1-byte PRNG requests.   This problem dates  back to SSLeay,  which
    OpenSSL is based on, and was found in other SSLeay-based  toolkits
    as well.   While a number  of enhancements have  been done to  the
    original  PRNG  during  the  development  of  OpenSSL, this design
    error was overlooked so far.

    The PRNG (implemented in source code file crypto/md_rand.c) uses a
    hash function,  by default  SHA-1, to  update its  internal secret
    state and to  generate output.   The secret state  consists of two
    components:   A  chaining  variable  'md',  sized according to the
    hash function's output  (160 bits for  SHA-1), and a  large buffer
    'state'.   'md'  is  always  replaced  by  a  hash function output
    during the PRNG's operation.   'state' is accessed circularly  and
    is used for storing additional entropy.

    When generating output  bytes, OpenSSL versions  up to 0.9.6a  set
    'md' to the hash of one half of its previous value and some  other
    data, including  bytes from  'state'.   The design  error was that
    the half  of 'md'  input to  the hash  function was  the same half
    that was  also used  as PRNG  output, meaning  that it  in general
    cannot be considered secret.   Also the number of bytes  used from
    'state' depended on the number  of bytes requested as PRNG  output
    and  could  be  as  small  as  one,  allowing for easy brute-force
    analysis of all possible cases.  The combination of these  effects
    made it possible to  reconstruct the complete internal  PRNG state
    from the output  of one PRNG  request appropriately sized  to gain
    knowledge  on  'md'  followed  by  enough  consecutive 1-byte PRNG
    requests to traverse all of 'state'.

    It is unlikely for applications to request PRNG bytes in a pattern
    allowing  for  the  attack  against  the OpenSSL PRNG.  Typically,
    applications  will  request  PRNG  bytes  in  larger  chunks.   No
    applications is known to us which is actually vulnerable.

    However, the PRNG design flaw is a significant weakness: The  PRNG
    does not provide the intended strength under all circumstances.

SOLUTION

    OpenSSL 0.9.6b has been corrected and does not require this patch.
    The  source  code   of  OpenSSL  0.9.6b   is  available  as   file
    openssl-0.9.6b.tar.gz from

        ftp://ftp.openssl.org/source

    If you were previously using the "engine" release of OpenSSL 0.9.6
    or 0.9.6a, obtain file openssl-engine-0.9.6b.tar.gz instead.

    OpenSSL 0.9.6b changes the PRNG implementation as follows to  give
    the PRNG its intended strength:
    1. When updating  'md' during PRNG  output generation, all  of the
       previous 'md' value is hashed, including the secret half.
    2. Also, the number of  bytes from 'state' included into  the hash
       is now independent from the number of PRNG bytes requested.

    The first measure alone would be sufficient to solve the  problem.
    The second measure  makes sure that  additional data from  'state'
    is never mixed  in in small  portions; this heuristically  further
    strengthens the PRNG.

    If upgrading to  OpenSSL 0.9.6b is  not immediately possible,  the
    following patch  should be  applied to  file crypto/rand/md_rand.c
    in the OpenSSL  source code tree.   (The patch is  compatible with
    OpenSSL versions 0.9.5  up to 0.9.6a.)   This changes the  PRNG in
    two ways, as discussed above.

    --- md_rand.c
    +++ md_rand.c
    @@ -313,6 +313,7 @@
 	    {
 	    static volatile int stirred_pool = 0;
 	    int i,j,k,st_num,st_idx;
    +	int num_ceil;
 	    int ok;
 	    long md_c[2];
 	    unsigned char local_md[MD_DIGEST_LENGTH];
    @@ -333,6 +334,12 @@
 		    }
     #endif

    +	if (num <= 0)
    +		return 1;
    +
    +	/* round upwards to multiple of MD_DIGEST_LENGTH/2 */
    +	num_ceil = (1 + (num-1)/(MD_DIGEST_LENGTH/2)) * (MD_DIGEST_LENGTH/2);
    +
 	    /*
 	     * (Based on the rand(3) manpage:)
 	     *
    @@ -418,11 +425,11 @@
 	    md_c[1] = md_count[1];
 	    memcpy(local_md, md, sizeof md);

    -	state_index+=num;
    +	state_index+=num_ceil;
 	    if (state_index > state_num)
 		    state_index %= state_num;

    -	/* state[st_idx], ..., state[(st_idx + num - 1) % st_num]
    +	/* state[st_idx], ..., state[(st_idx + num_ceil - 1) % st_num]
 	     * are now ours (but other threads may use them too) */

 	    md_count[0] += 1;
    @@ -434,6 +441,7 @@

 	    while (num > 0)
 		    {
    +		/* num_ceil -= MD_DIGEST_LENGTH/2 */
 		    j=(num >= MD_DIGEST_LENGTH/2)?MD_DIGEST_LENGTH/2:num;
 		    num-=j;
 		    MD_Init(&m);
    @@ -444,27 +452,28 @@
 			    curr_pid = 0;
 			    }
     #endif
    -		MD_Update(&m,&(local_md[MD_DIGEST_LENGTH/2]),MD_DIGEST_LENGTH/2);
    +		MD_Update(&m,local_md,MD_DIGEST_LENGTH);
 		    MD_Update(&m,(unsigned char *)&(md_c[0]),sizeof(md_c));
     #ifndef PURIFY
 		    MD_Update(&m,buf,j); /* purify complains */
     #endif
    -		k=(st_idx+j)-st_num;
    +		k=(st_idx+MD_DIGEST_LENGTH/2)-st_num;
 		    if (k > 0)
 			    {
    -			MD_Update(&m,&(state[st_idx]),j-k);
    +			MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2-k);
 			    MD_Update(&m,&(state[0]),k);
 			    }
 		    else
    -			MD_Update(&m,&(state[st_idx]),j);
    +			MD_Update(&m,&(state[st_idx]),MD_DIGEST_LENGTH/2);
 		    MD_Final(local_md,&m);

    -		for (i=0; i<j; i++)
    +		for (i=0; i<MD_DIGEST_LENGTH/2; i++)
 			    {
 			    state[st_idx++]^=local_md[i]; /* may compete with other threads */
    -			*(buf++)=local_md[i+MD_DIGEST_LENGTH/2];
 			    if (st_idx >= st_num)
 				    st_idx=0;
    +			if (i < j)
    +				*(buf++)=local_md[i+MD_DIGEST_LENGTH/2];
 			    }
 		    }

    For Trustix Secure Linux:

        http://www.trustix.net/pub/Trustix/updates/
        ftp://ftp.trustix.net/pub/Trustix/updates/
        ftp://ftp.trustix.net/pub/Trustix/software/swup/
           ./1.2/SRPMS/openssl-0.9.6-2tr.src.rpm
           ./1.2/RPMS/openssl-devel-0.9.6-2tr.i586.rpm
           ./1.2/RPMS/openssl-0.9.6-2tr.i586.rpm
           ./1.1/SRPMS/openssl-0.9.5a-2tr.src.rpm
           ./1.1/RPMS/openssl-devel-0.9.5a-2tr.i586.rpm
           ./1.1/RPMS/openssl-0.9.5a-2tr.i586.rpm

    For EnGarde Secure Linux:

        ftp://ftp.engardelinux.org/pub/engarde/stable/updates/
        http://ftp.engardelinux.org/pub/engarde/stable/updates/
           SRPMS/openssl-0.9.6-1.0.14.src.rpm
           i386/openssl-0.9.6-1.0.14.i386.rpm
           i386/openssl-devel-0.9.6-1.0.14.i386.rpm
           i386/openssl-misc-0.9.6-1.0.14.i386.rpm
           i686/openssl-0.9.6-1.0.14.i686.rpm
           i686/openssl-devel-0.9.6-1.0.14.i686.rpm
           i686/openssl-misc-0.9.6-1.0.14.i686.rpm

    For Red Hat:

        ftp://updates.redhat.com/6.2/en/os/SRPMS/openssl-0.9.5a-7.6.x.src.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/openssl-0.9.5a-7.6.x.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/openssl-devel-0.9.5a-7.6.x.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/openssl-perl-0.9.5a-7.6.x.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/alpha/openssl-python-0.9.5a-7.6.x.alpha.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/openssl-0.9.5a-7.6.x.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/openssl-devel-0.9.5a-7.6.x.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/openssl-perl-0.9.5a-7.6.x.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/i386/openssl-python-0.9.5a-7.6.x.i386.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/openssl-0.9.5a-7.6.x.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/openssl-devel-0.9.5a-7.6.x.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/openssl-perl-0.9.5a-7.6.x.sparc.rpm
        ftp://updates.redhat.com/6.2/en/os/sparc/openssl-python-0.9.5a-7.6.x.sparc.rpm
        ftp://updates.redhat.com/7.0/en/os/SRPMS/openssl095a-0.9.5a-9.src.rpm
        ftp://updates.redhat.com/7.0/en/os/SRPMS/openssl-0.9.6-9.src.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/openssl095a-0.9.5a-9.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/openssl-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/openssl-devel-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/openssl-perl-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/alpha/openssl-python-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/openssl095a-0.9.5a-9.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/openssl-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/openssl-devel-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/openssl-perl-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.0/en/os/i386/openssl-python-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/SRPMS/openssl095a-0.9.5a-9.src.rpm
        ftp://updates.redhat.com/7.1/en/os/SRPMS/openssl-0.9.6-9.src.rpm
        ftp://updates.redhat.com/7.1/en/os/SRPMS/nss_ldap-149-4.src.rpm
        ftp://updates.redhat.com/7.1/en/os/alpha/openssl095a-0.9.5a-9.alpha.rpm
        ftp://updates.redhat.com/7.1/en/os/alpha/openssl-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.1/en/os/alpha/openssl-devel-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.1/en/os/alpha/openssl-perl-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.1/en/os/alpha/openssl-python-0.9.6-9.alpha.rpm
        ftp://updates.redhat.com/7.1/en/os/alpha/nss_ldap-149-4.alpha.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/openssl095a-0.9.5a-9.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/openssl-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/openssl-devel-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/openssl-perl-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/openssl-python-0.9.6-9.i386.rpm
        ftp://updates.redhat.com/7.1/en/os/i386/nss_ldap-149-4.i386.rpm

    Systems  running  NetBSD-current  dated  from  before   2001-07-10
    should be  upgraded to  NetBSD-current dated  2001-07-11 or later.
    Systems  running  NetBSD  1.5  or  1.5.1 sources dated from before
    2001-07-29  should  be  upgraded  from  NetBSD 1.5.x sources dated
    2001-07-30 or later.  NetBSD 1.5.2 is not vulnerable.