Fix server session ID handling with ticket
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 848c04f..59c91c4 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -439,10 +439,16 @@
     /* Remember the client asked us to send a ticket */
     ssl->handshake->new_session_ticket = 1;
 
+    SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) );
+
     if( len == 0 )
         return( 0 );
 
-    SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) );
+    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE )
+    {
+        SSL_DEBUG_MSG( 3, ( "ticket rejected: renegotiating" ) );
+        return( 0 );
+    }
 
     /*
      * Use a temporary session to preserve the current one of failures.
@@ -456,6 +462,13 @@
 
     SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) );
 
+    /*
+     * Keep the session ID sent by the client, since we MUST send it back to
+     * inform him we're accepting the ticket  (RFC 5077 section 3.4)
+     */
+    session.length = ssl->session_negotiate->length;
+    memcpy( &session.id, ssl->session_negotiate->id, session.length );
+
     ssl_session_free( ssl->session_negotiate );
     memcpy( ssl->session_negotiate, &session, sizeof( ssl_session ) );
     memset( &session, 0, sizeof( ssl_session ) );
@@ -1284,36 +1297,44 @@
     SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 );
 
     /*
-     *    38  .  38     session id length
-     *    39  . 38+n    session id
-     *   39+n . 40+n    chosen ciphersuite
-     *   41+n . 41+n    chosen compression alg.
-     *   42+n . 43+n    extensions length
-     *   44+n . 43+n+m  extensions
+     * Resume is 0  by default, see ssl_handshake_init().
+     * It may be already set to 1 by ssl_parse_session_ticket_ext().
+     * If not, try looking up session ID in our cache.
      */
-    ssl->session_negotiate->length = n = 32;
-    *p++ = (unsigned char) ssl->session_negotiate->length;
+    if( ssl->handshake->resume == 0 &&
+        ssl->renegotiation == SSL_INITIAL_HANDSHAKE &&
+        ssl->f_get_cache != NULL &&
+        ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) == 0 )
+    {
+        ssl->handshake->resume = 1;
+    }
 
-    if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ||
-        ssl->f_get_cache == NULL ||
-        ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) != 0 )
+    if( ssl->handshake->resume == 0 )
     {
         /*
-         * Not found, create a new session id
+         * New session, create a new session id,
+         * unless we're about to issue a session ticket
          */
-        ssl->handshake->resume = 0;
         ssl->state++;
 
-        if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id,
-                                n ) ) != 0 )
-            return( ret );
+        if( ssl->handshake->new_session_ticket == 0 )
+        {
+            ssl->session_negotiate->length = n = 32;
+            if( ( ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id,
+                            n ) ) != 0 )
+                return( ret );
+        }
+        else
+        {
+            ssl->session_negotiate->length = 0;
+            memset( ssl->session_negotiate->id, 0, 32 );
+        }
     }
     else
     {
         /*
-         * Found a matching session, resuming it
+         * Resuming a session
          */
-        ssl->handshake->resume = 1;
         ssl->state = SSL_SERVER_CHANGE_CIPHER_SPEC;
 
         if( ( ret = ssl_derive_keys( ssl ) ) != 0 )
@@ -1323,6 +1344,15 @@
         }
     }
 
+    /*
+     *    38  .  38     session id length
+     *    39  . 38+n    session id
+     *   39+n . 40+n    chosen ciphersuite
+     *   41+n . 41+n    chosen compression alg.
+     *   42+n . 43+n    extensions length
+     *   44+n . 43+n+m  extensions
+     */
+    *p++ = (unsigned char) ssl->session_negotiate->length;
     memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->length );
     p += ssl->session_negotiate->length;