|
5 | 5 | import java.io.InputStream; |
6 | 6 | import java.io.OutputStream; |
7 | 7 | import java.security.SecureRandom; |
| 8 | +import java.util.Hashtable; |
8 | 9 | import java.util.Vector; |
9 | 10 |
|
10 | 11 | import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; |
@@ -151,7 +152,7 @@ protected void handleHandshakeMessage(short type, byte[] data) |
151 | 152 | if (this.securityParameters.cipherSuite != this.sessionParameters.getCipherSuite() |
152 | 153 | || this.securityParameters.compressionAlgorithm != this.sessionParameters.getCompressionAlgorithm()) |
153 | 154 | { |
154 | | - throw new TlsFatalAlert(AlertDescription.internal_error); |
| 155 | + throw new TlsFatalAlert(AlertDescription.illegal_parameter); |
155 | 156 | } |
156 | 157 | this.securityParameters.masterSecret = this.sessionParameters.getMasterSecret(); |
157 | 158 | this.securityParameters.pskIdentity = this.sessionParameters.getPSKIdentity(); |
@@ -631,8 +632,34 @@ protected void receiveClientHelloMessage(ByteArrayInputStream buf) |
631 | 632 | */ |
632 | 633 | if (this.resumedSession) |
633 | 634 | { |
634 | | - readExtensions(buf); // drop provided extensions... |
| 635 | + Hashtable newClientExtensions = readExtensions(buf); |
635 | 636 | this.clientExtensions = this.sessionParameters.readPeerExtensions(); |
| 637 | + /* |
| 638 | + * RFC 3546 indicates we MUST ignore extensions, but RFC 7627 Section 5.3 says: |
| 639 | + * o If the original session did not use the "extended_master_secret" |
| 640 | + * extension but the new ClientHello contains the extension, then the |
| 641 | + * server MUST NOT perform the abbreviated handshake. Instead, it |
| 642 | + * SHOULD continue with a full handshake (as described in |
| 643 | + * Section 5.2) to negotiate a new session. |
| 644 | + * |
| 645 | + * o If the original session used the "extended_master_secret" |
| 646 | + * extension but the new ClientHello does not contain it, the server |
| 647 | + * MUST abort the abbreviated handshake. |
| 648 | + */ |
| 649 | + boolean prevHasEMS = TlsExtensionsUtils.hasExtendedMasterSecretExtension(clientExtensions); |
| 650 | + boolean curHasEMS = TlsExtensionsUtils.hasExtendedMasterSecretExtension(newClientExtensions); |
| 651 | + if (curHasEMS != prevHasEMS) { |
| 652 | + if (!prevHasEMS) { |
| 653 | + /* |
| 654 | + * This is the case where we SHOULD continue with a full handshake... |
| 655 | + */ |
| 656 | + this.sessionParameters = null; |
| 657 | + this.tlsSession = null; |
| 658 | + this.resumedSession = false; |
| 659 | + this.clientExtensions = newClientExtensions; |
| 660 | + } else |
| 661 | + throw new TlsFatalAlert(AlertDescription.illegal_parameter); |
| 662 | + } |
636 | 663 | } |
637 | 664 | else |
638 | 665 | { |
@@ -835,18 +862,13 @@ protected void sendServerHelloMessage() |
835 | 862 | * RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore |
836 | 863 | * extensions appearing in the client hello, and send a server hello containing no |
837 | 864 | * extensions. |
| 865 | + * |
| 866 | + * The server hello containing no extensions is not entirely true. RFC 5746 explicitly |
| 867 | + * states out in 3.6. Server Behavior that the secure_renegotiation extensions is also |
| 868 | + * sent during session resumption. So we need to handle this part. |
838 | 869 | */ |
839 | | - |
840 | | - if (this.resumedSession) |
841 | | - { |
842 | | - applyMaxFragmentLengthExtension(); |
843 | | - |
844 | | - // we don't need the serverExtensions for resumed sessions. So we can leave here... |
845 | | - message.writeToRecordStream(); |
846 | | - return; |
847 | | - } |
848 | | - |
849 | | - this.serverExtensions = tlsServer.getServerExtensions(); |
| 870 | + if (!this.resumedSession) |
| 871 | + this.serverExtensions = tlsServer.getServerExtensions(); |
850 | 872 |
|
851 | 873 | /* |
852 | 874 | * RFC 5746 3.6. Server Behavior: Initial Handshake |
|
0 commit comments