Some helper fuctions for MicroTLS.
Esempio n. 1
0
        protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
        {
            {
                ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
                if (server_version.IsDtls)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                // Check that this matches what the server is Sending in the record layer
                if (!server_version.Equals(this.mRecordStream.ReadVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                ProtocolVersion client_version = Context.ClientVersion;
                if (!server_version.IsEqualOrEarlierVersionOf(client_version))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                this.mRecordStream.SetWriteVersion(server_version);
                ContextAdmin.SetServerVersion(server_version);
                this.mTlsClient.NotifyServerVersion(server_version);
            }

            /*
             * Read the server random
             */
            this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);

            this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
            if (this.mSelectedSessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
            this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null &&
                                   Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);

            /*
             * Find out which CipherSuite the server has chosen and check that it was one of the offered
             * ones, and is a valid selection for the negotiated version.
             */
            int selectedCipherSuite = TlsUtilities.ReadUint16(buf);

            if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);

            /*
             * Find out which CompressionMethod the server has chosen and check that it was one of the
             * offered ones.
             */
            byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);

            if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);

            /*
             * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
             * hello message when the client has requested extended functionality via the extended
             * client hello message specified in Section 2.1. ... Note that the extended server hello
             * message is only sent in response to an extended client hello message. This prevents the
             * possibility that the extended server hello message could "break" existing TLS 1.0
             * clients.
             */
            this.mServerExtensions = ReadExtensions(buf);

            /*
             * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
             * extended client hello message.
             *
             * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
             * Hello is always allowed.
             */
            if (this.mServerExtensions != null)
            {
                foreach (int extType in this.mServerExtensions.Keys)
                {
                    /*
                     * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
                     * ClientHello containing only the SCSV is an explicit exception to the prohibition
                     * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
                     * only allowed because the client is signaling its willingness to receive the
                     * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */
                    if (extType == ExtensionType.renegotiation_info)
                    {
                        continue;
                    }

                    /*
                     * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
                     * same extension type appeared in the corresponding ClientHello. If a client
                     * receives an extension type in ServerHello that it did not request in the
                     * associated ClientHello, it MUST abort the handshake with an unsupported_extension
                     * fatal alert.
                     */
                    if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
                    {
                        throw new TlsFatalAlert(AlertDescription.unsupported_extension);
                    }

                    /*
                     * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
                     * extensions appearing in the client hello, and Send a server hello containing no
                     * extensions[.]
                     */
                    if (this.mResumedSession)
                    {
                        // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
                        // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
                        // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
                        //                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }
                }
            }

            /*
             * RFC 5746 3.4. Client Behavior: Initial Handshake
             */
            {
                /*
                 * When a ServerHello is received, the client MUST check if it includes the
                 * "renegotiation_info" extension:
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * If the extension is present, set the secure_renegotiation flag to TRUE. The
                     * client MUST then verify that the length of the "renegotiated_connection"
                     * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal
                     * handshake_failure alert).
                     */
                    this.mSecureRenegotiation = true;

                    if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                    {
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }
                }
            }

            // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
            this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);

            IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;

            if (this.mResumedSession)
            {
                if (selectedCipherSuite != this.mSessionParameters.CipherSuite ||
                    selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                sessionClientExtensions = null;
                sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
            }

            this.mSecurityParameters.cipherSuite          = selectedCipherSuite;
            this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;

            if (sessionServerExtensions != null)
            {
                {
                    /*
                     * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
                     * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
                     * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
                     * client.
                     */
                    bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
                    if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
                    {
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }

                    this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
                }

                this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);

                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
                                                                                               sessionServerExtensions, AlertDescription.illegal_parameter);

                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
                 * a session resumption handshake.
                 */
                this.mAllowCertificateStatus = !this.mResumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.illegal_parameter);

                this.mExpectSessionTicket = !this.mResumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.illegal_parameter);
            }

            /*
             * TODO[session-hash]
             *
             * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
             * that do not use the extended master secret [..]. (and see 5.2, 5.3)
             */

            if (sessionClientExtensions != null)
            {
                this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
            }

            this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);

            /*
             * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
             * verify_data_length has a verify_data_length equal to 12. This includes all
             * existing cipher suites.
             */
            this.mSecurityParameters.verifyDataLength = 12;
        }
Esempio n. 2
0
 protected virtual bool ExpectCertificateVerifyMessage()
 {
     return(mClientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)mClientCertificateType));
 }
 protected internal static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection)
 {
     return(TlsUtilities.EncodeOpaque8(renegotiated_connection));
 }
 public virtual void Encode(Stream output)
 {
     TlsUtilities.WriteUint8(this.mMode, output);
 }
Esempio n. 5
0
        protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
        {
            ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);

            mRecordStream.SetWriteVersion(client_version);

            if (client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            byte[] client_random = TlsUtilities.ReadFully(32, buf);

            /*
             * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to
             * use the Session ID in the ClientHello for stateful session resumption.
             */
            byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
            if (sessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            /*
             * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
             * resumption request), this vector MUST include at least the cipher_suite from that
             * session.
             */
            int cipher_suites_length = TlsUtilities.ReadUint16(buf);

            if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
            {
                throw new TlsFatalAlert(AlertDescription.decode_error);
            }

            this.mOfferedCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);

            /*
             * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
             * resumption request), it MUST include the compression_method from that session.
             */
            int compression_methods_length = TlsUtilities.ReadUint8(buf);

            if (compression_methods_length < 1)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            this.mOfferedCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and Send a server hello containing no
             * extensions.
             */
            this.mClientExtensions = ReadExtensions(buf);

            /*
             * TODO[resumption] Check RFC 7627 5.4. for required behaviour
             */

            /*
             * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
             * master secret [..]. (and see 5.2, 5.3)
             */
            this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
            if (!mSecurityParameters.IsExtendedMasterSecret && mTlsServer.RequiresExtendedMasterSecret())
            {
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            ContextAdmin.SetClientVersion(client_version);

            mTlsServer.NotifyClientVersion(client_version);
            mTlsServer.NotifyFallback(Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));

            mSecurityParameters.clientRandom = client_random;

            mTlsServer.NotifyOfferedCipherSuites(mOfferedCipherSuites);
            mTlsServer.NotifyOfferedCompressionMethods(mOfferedCompressionMethods);

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */

                /*
                 * When a ClientHello is received, the server MUST check if it includes the
                 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
                 * to TRUE.
                 */
                if (Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
                {
                    this.mSecureRenegotiation = true;
                }

                /*
                 * The server MUST check if the "renegotiation_info" extension is included in the
                 * ClientHello.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * If the extension is present, set secure_renegotiation flag to TRUE. The
                     * server MUST then verify that the length of the "renegotiated_connection"
                     * field is zero, and if it is not, MUST abort the handshake.
                     */
                    this.mSecureRenegotiation = true;

                    if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                    {
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }
                }
            }

            mTlsServer.NotifySecureRenegotiation(this.mSecureRenegotiation);

            if (mClientExtensions != null)
            {
                // NOTE: Validates the padding extension data, if present
                TlsExtensionsUtilities.GetPaddingExtension(mClientExtensions);

                mTlsServer.ProcessClientExtensions(mClientExtensions);
            }
        }
Esempio n. 6
0
        protected virtual byte[] GenerateServerHello(ServerHandshakeState state)
        {
            SecurityParameters securityParameters = state.serverContext.SecurityParameters;

            MemoryStream buf = new MemoryStream();

            {
                ProtocolVersion server_version = state.server.GetServerVersion();
                if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                // TODO Read RFCs for guidance on the expected record layer version number
                // recordStream.setReadVersion(server_version);
                // recordStream.setWriteVersion(server_version);
                // recordStream.setRestrictReadVersion(true);
                state.serverContext.SetServerVersion(server_version);

                TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf);
            }

            buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length);

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf);

            int selectedCipherSuite = state.server.GetSelectedCipherSuite();

            if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error);
            securityParameters.cipherSuite = selectedCipherSuite;

            byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod();

            if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            securityParameters.compressionAlgorithm = selectedCompressionMethod;

            TlsUtilities.WriteUint16(selectedCipherSuite, buf);
            TlsUtilities.WriteUint8(selectedCompressionMethod, buf);

            state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.server.GetServerExtensions());

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (state.secure_renegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * Note that sending a "renegotiation_info" extension in response to a ClientHello
                     * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
                     * Section 7.4.1.4, on the server sending unsolicited extensions and is only allowed
                     * because the client is signaling its willingness to receive the extension via the
                     * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */

                    /*
                     * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (securityParameters.IsExtendedMasterSecret)
            {
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions);
            }

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and send a server hello containing no
             * extensions.
             */

            if (state.serverExtensions.Count > 0)
            {
                securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions);

                securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession,
                                                                                          state.clientExtensions, state.serverExtensions, AlertDescription.internal_error);

                securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
                 * a session resumption handshake.
                 */
                state.allowCertificateStatus = !state.resumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.internal_error);

                state.expectSessionTicket = !state.resumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.internal_error);

                TlsProtocol.WriteExtensions(buf, state.serverExtensions);
            }

            securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext,
                                                                          securityParameters.CipherSuite);

            /*
             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length
             * has a verify_data_length equal to 12. This includes all existing cipher suites.
             */
            securityParameters.verifyDataLength = 12;

            return(buf.ToArray());
        }
Esempio n. 7
0
 protected virtual bool ExpectCertificateVerifyMessage(ServerHandshakeState state)
 {
     return(state.clientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)state.clientCertificateType));
 }
Esempio n. 8
0
 public static BigInteger ReadDHParameter(Stream input)
 {
     return(new BigInteger(1, TlsUtilities.ReadOpaque16(input)));
 }
Esempio n. 9
0
 public static void WriteDHParameter(BigInteger x, Stream output)
 {
     TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output);
 }
Esempio n. 10
0
 internal CombinedHash()
 {
     this.mMd5  = TlsUtilities.CreateHash(HashAlgorithm.md5);
     this.mSha1 = TlsUtilities.CreateHash(HashAlgorithm.sha1);
 }
Esempio n. 11
0
 internal CombinedHash(CombinedHash t)
 {
     this.mContext = t.mContext;
     this.mMd5     = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5);
     this.mSha1    = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1);
 }
Esempio n. 12
0
        public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize)
        {
            this.context    = context;
            this.randomData = new byte[256];
            context.NonceRandomGenerator.NextBytes(this.randomData);
            this.useExplicitIV  = TlsUtilities.IsTlsV11(context);
            this.encryptThenMac = context.SecurityParameters.encryptThenMac;
            int num = 2 * cipherKeySize + clientWriteDigest.GetDigestSize() + serverWriteDigest.GetDigestSize();

            if (!this.useExplicitIV)
            {
                num += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize();
            }
            byte[] array  = TlsUtilities.CalculateKeyBlock(context, num);
            int    num2   = 0;
            TlsMac tlsMac = new TlsMac(context, clientWriteDigest, array, num2, clientWriteDigest.GetDigestSize());

            num2 += clientWriteDigest.GetDigestSize();
            TlsMac tlsMac2 = new TlsMac(context, serverWriteDigest, array, num2, serverWriteDigest.GetDigestSize());

            num2 += serverWriteDigest.GetDigestSize();
            KeyParameter parameters = new KeyParameter(array, num2, cipherKeySize);

            num2 += cipherKeySize;
            KeyParameter parameters2 = new KeyParameter(array, num2, cipherKeySize);

            num2 += cipherKeySize;
            byte[] iv;
            byte[] iv2;
            if (this.useExplicitIV)
            {
                iv  = new byte[clientWriteCipher.GetBlockSize()];
                iv2 = new byte[serverWriteCipher.GetBlockSize()];
            }
            else
            {
                iv    = Arrays.CopyOfRange(array, num2, num2 + clientWriteCipher.GetBlockSize());
                num2 += clientWriteCipher.GetBlockSize();
                iv2   = Arrays.CopyOfRange(array, num2, num2 + serverWriteCipher.GetBlockSize());
                num2 += serverWriteCipher.GetBlockSize();
            }
            if (num2 != num)
            {
                throw new TlsFatalAlert(80);
            }
            ICipherParameters parameters3;
            ICipherParameters parameters4;

            if (context.IsServer)
            {
                this.mWriteMac     = tlsMac2;
                this.mReadMac      = tlsMac;
                this.encryptCipher = serverWriteCipher;
                this.decryptCipher = clientWriteCipher;
                parameters3        = new ParametersWithIV(parameters2, iv2);
                parameters4        = new ParametersWithIV(parameters, iv);
            }
            else
            {
                this.mWriteMac     = tlsMac;
                this.mReadMac      = tlsMac2;
                this.encryptCipher = clientWriteCipher;
                this.decryptCipher = serverWriteCipher;
                parameters3        = new ParametersWithIV(parameters, iv);
                parameters4        = new ParametersWithIV(parameters2, iv2);
            }
            this.encryptCipher.Init(true, parameters3);
            this.decryptCipher.Init(false, parameters4);
        }
Esempio n. 13
0
        public override void ProcessServerCertificate(AbstractCertificate serverCertificate)
        {
            if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }
            if (serverCertificate.IsEmpty)
            {
                throw new TlsFatalAlert(AlertDescription.decode_error);
            }

            Certificate real = serverCertificate  as Certificate;
            X509CertificateStructure x509Cert = null;

            if (real != null)
            {
                x509Cert = real.GetCertificateAt(0);
            }

            SubjectPublicKeyInfo keyInfo = serverCertificate.SubjectPublicKeyInfo();

            try
            {
                this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
            }
            catch (Exception e)
            {
                throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
            }

            if (mTlsSigner == null)
            {
                try
                {
                    this.mDHAgreePublicKey = (DHPublicKeyParameters)this.mServerPublicKey;
                    this.mDHParameters     = mDHAgreePublicKey.Parameters;
                }
                catch (InvalidCastException e)
                {
                    throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
                }

                if (x509Cert != null)
                {
                    TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
                }
            }
            else
            {
                if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
                {
                    throw new TlsFatalAlert(AlertDescription.certificate_unknown);
                }

                if (x509Cert != null)
                {
                    TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
                }
            }

            base.ProcessServerCertificate(serverCertificate);
        }
Esempio n. 14
0
        protected virtual void SendClientHelloMessage()
        {
            this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);

            ProtocolVersion client_version = this.mTlsClient.ClientVersion;

            if (client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            ContextAdmin.SetClientVersion(client_version);

            /*
             * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
             * Session ID in the TLS ClientHello.
             */
            byte[] session_id = TlsUtilities.EmptyBytes;
            if (this.mTlsSession != null)
            {
                session_id = this.mTlsSession.SessionID;
                if (session_id == null || session_id.Length > 32)
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            bool fallback = this.mTlsClient.IsFallback;

            this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();

            this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();

            if (session_id.Length > 0 && this.mSessionParameters != null)
            {
                if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite) ||
                    !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
                {
                    session_id = TlsUtilities.EmptyBytes;
                }
            }

            this.mClientExtensions = this.mTlsClient.GetClientExtensions();

            HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);

            TlsUtilities.WriteVersion(client_version, message);

            message.Write(this.mSecurityParameters.ClientRandom);

            TlsUtilities.WriteOpaque8(session_id, message);

            // Cipher Suites (and SCSV)
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);

                if (noRenegExt && noRenegScsv)
                {
                    // TODO Consider whether to default to a client extension instead
                    //                this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
                    //                this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
                }

                /*
                 * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version
                 * containing a lower value than the latest (highest-valued) version supported by the
                 * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in
                 * ClientHello.cipher_suites.
                 */
                if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
                {
                    this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
                }

                TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
            }

            TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);

            if (mClientExtensions != null)
            {
                WriteExtensions(message, mClientExtensions);
            }

            message.WriteToRecordStream(this);
        }
Esempio n. 15
0
        /// <summary>Connects to the remote system.</summary>
        /// <param name="verifyer">Will be used when a certificate is received to verify
        /// that this certificate is accepted by the client.</param>
        /// <exception cref="IOException">If handshake was not successful</exception>
        public virtual void Connect(
            ICertificateVerifyer verifyer)
        {
            this.verifyer = verifyer;

            /*
             * Send Client hello
             *
             * First, generate some random data.
             */
            this.clientRandom = new byte[32];

            /*
             * TLS 1.0 requires a unix-timestamp in the first 4 bytes
             */
            int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);

            this.clientRandom[0] = (byte)(t >> 24);
            this.clientRandom[1] = (byte)(t >> 16);
            this.clientRandom[2] = (byte)(t >> 8);
            this.clientRandom[3] = (byte)t;

            random.NextBytes(this.clientRandom, 4, 28);


            MemoryStream outStr = new MemoryStream();

            TlsUtilities.WriteVersion(outStr);
            outStr.Write(this.clientRandom, 0, this.clientRandom.Length);

            /*
             * Length of Session id
             */
            TlsUtilities.WriteUint8((short)0, outStr);

            /*
             * Cipher suites
             */
            TlsCipherSuiteManager.WriteCipherSuites(outStr);

            /*
             * Compression methods, just the null method.
             */
            byte[] compressionMethods = new byte[] { 0x00 };
            TlsUtilities.WriteUint8((short)compressionMethods.Length, outStr);
            outStr.Write(compressionMethods, 0, compressionMethods.Length);


            MemoryStream bos = new MemoryStream();

            TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos);
            TlsUtilities.WriteUint24((int)outStr.Length, bos);
            byte[] outBytes = outStr.ToArray();
            bos.Write(outBytes, 0, outBytes.Length);
            byte[] message = bos.ToArray();
            rs.WriteMessage(RL_HANDSHAKE, message, 0, message.Length);
            connection_state = CS_CLIENT_HELLO_SEND;

            /*
             * We will now read data, until we have completed the handshake.
             */
            while (connection_state != CS_DONE)
            {
                rs.ReadData();
            }

            this.tlsInputStream  = new TlsInputStream(this);
            this.tlsOutputStream = new TlsOuputStream(this);
        }
Esempio n. 16
0
 public static byte[] GetNegotiatedDheGroupsClientExtension(IDictionary extensions)
 {
     byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups);
     return((extensionData != null) ? ReadNegotiatedDheGroupsClientExtension(extensionData) : null);
 }
Esempio n. 17
0
        /// <exception cref="IOException"></exception>
        public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher,
                              IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize)
        {
            this.context = context;

            this.randomData = new byte[256];
            context.NonceRandomGenerator.NextBytes(randomData);

            this.useExplicitIV  = TlsUtilities.IsTlsV11(context);
            this.encryptThenMac = context.SecurityParameters.encryptThenMac;

            int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize()
                                 + serverWriteDigest.GetDigestSize();

            // From TLS 1.1 onwards, block ciphers don't need client_write_IV
            if (!useExplicitIV)
            {
                key_block_size += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize();
            }

            byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);

            int offset = 0;

            TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset,
                                               clientWriteDigest.GetDigestSize());

            offset += clientWriteDigest.GetDigestSize();
            TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset,
                                               serverWriteDigest.GetDigestSize());

            offset += serverWriteDigest.GetDigestSize();

            KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);

            offset += cipherKeySize;
            KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);

            offset += cipherKeySize;

            byte[] client_write_IV, server_write_IV;
            if (useExplicitIV)
            {
                client_write_IV = new byte[clientWriteCipher.GetBlockSize()];
                server_write_IV = new byte[serverWriteCipher.GetBlockSize()];
            }
            else
            {
                client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + clientWriteCipher.GetBlockSize());
                offset         += clientWriteCipher.GetBlockSize();
                server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + serverWriteCipher.GetBlockSize());
                offset         += serverWriteCipher.GetBlockSize();
            }

            if (offset != key_block_size)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            ICipherParameters encryptParams, decryptParams;

            if (context.IsServer)
            {
                this.mWriteMac     = serverWriteMac;
                this.mReadMac      = clientWriteMac;
                this.encryptCipher = serverWriteCipher;
                this.decryptCipher = clientWriteCipher;
                encryptParams      = new ParametersWithIV(server_write_key, server_write_IV);
                decryptParams      = new ParametersWithIV(client_write_key, client_write_IV);
            }
            else
            {
                this.mWriteMac     = clientWriteMac;
                this.mReadMac      = serverWriteMac;
                this.encryptCipher = clientWriteCipher;
                this.decryptCipher = serverWriteCipher;
                encryptParams      = new ParametersWithIV(client_write_key, client_write_IV);
                decryptParams      = new ParametersWithIV(server_write_key, server_write_IV);
            }

            this.encryptCipher.Init(true, encryptParams);
            this.decryptCipher.Init(false, decryptParams);
        }
Esempio n. 18
0
 public static short GetNegotiatedDheGroupsServerExtension(IDictionary extensions)
 {
     byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups);
     return((short)((extensionData != null) ? ReadNegotiatedDheGroupsServerExtension(extensionData) : (-1)));
 }
Esempio n. 19
0
        protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body)
        {
            MemoryStream buf = new MemoryStream(body, false);

            // TODO Read RFCs for guidance on the expected record layer version number
            ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);

            if (!client_version.IsDtls)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            /*
             * Read the client random
             */
            byte[] client_random = TlsUtilities.ReadFully(32, buf);

            byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
            if (sessionID.Length > 32)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347
            byte[] cookie = TlsUtilities.ReadOpaque8(buf);

            int cipher_suites_length = TlsUtilities.ReadUint16(buf);

            if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
            {
                throw new TlsFatalAlert(AlertDescription.decode_error);
            }

            /*
             * NOTE: "If the session_id field is not empty (implying a session resumption request) this
             * vector must include at least the cipher_suite from that session."
             */
            state.offeredCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);

            int compression_methods_length = TlsUtilities.ReadUint8(buf);

            if (compression_methods_length < 1)
            {
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            state.offeredCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and send a server hello containing no
             * extensions.
             */
            state.clientExtensions = TlsProtocol.ReadExtensions(buf);

            TlsServerContextImpl context            = state.serverContext;
            SecurityParameters   securityParameters = context.SecurityParameters;

            /*
             * TODO[resumption] Check RFC 7627 5.4. for required behaviour
             */

            /*
             * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
             * master secret [..]. (and see 5.2, 5.3)
             */
            securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions);
            if (!securityParameters.IsExtendedMasterSecret && state.server.RequiresExtendedMasterSecret())
            {
                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            context.SetClientVersion(client_version);

            state.server.NotifyClientVersion(client_version);
            state.server.NotifyFallback(Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));

            securityParameters.clientRandom = client_random;

            state.server.NotifyOfferedCipherSuites(state.offeredCipherSuites);
            state.server.NotifyOfferedCompressionMethods(state.offeredCompressionMethods);

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            {
                /*
                 * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
                 * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
                 * ClientHello. Including both is NOT RECOMMENDED.
                 */

                /*
                 * When a ClientHello is received, the server MUST check if it includes the
                 * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
                 * to TRUE.
                 */
                if (Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
                {
                    state.secure_renegotiation = true;
                }

                /*
                 * The server MUST check if the "renegotiation_info" extension is included in the
                 * ClientHello.
                 */
                byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, ExtensionType.renegotiation_info);
                if (renegExtData != null)
                {
                    /*
                     * If the extension is present, set secure_renegotiation flag to TRUE. The
                     * server MUST then verify that the length of the "renegotiated_connection"
                     * field is zero, and if it is not, MUST abort the handshake.
                     */
                    state.secure_renegotiation = true;

                    if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
                    {
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }
                }
            }

            state.server.NotifySecureRenegotiation(state.secure_renegotiation);

            if (state.clientExtensions != null)
            {
                // NOTE: Validates the padding extension data, if present
                TlsExtensionsUtilities.GetPaddingExtension(state.clientExtensions);

                state.server.ProcessClientExtensions(state.clientExtensions);
            }
        }
Esempio n. 20
0
        /// <exception cref="IOException"></exception>
        public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher,
                             int cipherKeySize, int macSize)
        {
            if (!TlsUtilities.IsTlsV12(context))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            this.context = context;
            this.macSize = macSize;

            // NOTE: Valid for RFC 5288/6655 ciphers but may need review for other AEAD ciphers
            this.nonce_explicit_length = 8;

            // TODO SecurityParameters.fixed_iv_length
            int fixed_iv_length = 4;

            int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length);

            byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size);

            int offset = 0;

            KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize);

            offset += cipherKeySize;
            KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize);

            offset += cipherKeySize;
            byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
            offset += fixed_iv_length;
            byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length);
            offset += fixed_iv_length;

            if (offset != key_block_size)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            KeyParameter encryptKey, decryptKey;

            if (context.IsServer)
            {
                this.encryptCipher        = serverWriteCipher;
                this.decryptCipher        = clientWriteCipher;
                this.encryptImplicitNonce = server_write_IV;
                this.decryptImplicitNonce = client_write_IV;
                encryptKey = server_write_key;
                decryptKey = client_write_key;
            }
            else
            {
                this.encryptCipher        = clientWriteCipher;
                this.decryptCipher        = serverWriteCipher;
                this.encryptImplicitNonce = client_write_IV;
                this.decryptImplicitNonce = server_write_IV;
                encryptKey = client_write_key;
                decryptKey = server_write_key;
            }

            byte[] dummyNonce = new byte[fixed_iv_length + nonce_explicit_length];

            this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce));
            this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce));
        }
Esempio n. 21
0
        internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer)
        {
            SecurityParameters    securityParameters = state.serverContext.SecurityParameters;
            DtlsReliableHandshake handshake          = new DtlsReliableHandshake(state.serverContext, recordLayer,
                                                                                 state.server.GetHandshakeTimeoutMillis());

            DtlsReliableHandshake.Message clientMessage = handshake.ReceiveMessage();

            // NOTE: DTLSRecordLayer requires any DTLS version, we don't otherwise constrain this
            //ProtocolVersion recordLayerVersion = recordLayer.ReadVersion;

            if (clientMessage.Type == HandshakeType.client_hello)
            {
                ProcessClientHello(state, clientMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            {
                byte[] serverHelloBody = GenerateServerHello(state);

                ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength);

                ProtocolVersion recordLayerVersion = state.serverContext.ServerVersion;
                recordLayer.ReadVersion = recordLayerVersion;
                recordLayer.SetWriteVersion(recordLayerVersion);

                handshake.SendMessage(HandshakeType.server_hello, serverHelloBody);
            }

            handshake.NotifyHelloComplete();

            IList serverSupplementalData = state.server.GetServerSupplementalData();

            if (serverSupplementalData != null)
            {
                byte[] supplementalDataBody = GenerateSupplementalData(serverSupplementalData);
                handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody);
            }

            state.keyExchange = state.server.GetKeyExchange();
            state.keyExchange.Init(state.serverContext);

            state.serverCredentials = state.server.GetCredentials();

            Certificate serverCertificate = null;

            if (state.serverCredentials == null)
            {
                state.keyExchange.SkipServerCredentials();
            }
            else
            {
                state.keyExchange.ProcessServerCredentials(state.serverCredentials);

                serverCertificate = state.serverCredentials.Certificate;
                byte[] certificateBody = GenerateCertificate(serverCertificate);
                handshake.SendMessage(HandshakeType.certificate, certificateBody);
            }

            // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
            if (serverCertificate == null || serverCertificate.IsEmpty)
            {
                state.allowCertificateStatus = false;
            }

            if (state.allowCertificateStatus)
            {
                CertificateStatus certificateStatus = state.server.GetCertificateStatus();
                if (certificateStatus != null)
                {
                    byte[] certificateStatusBody = GenerateCertificateStatus(state, certificateStatus);
                    handshake.SendMessage(HandshakeType.certificate_status, certificateStatusBody);
                }
            }

            byte[] serverKeyExchange = state.keyExchange.GenerateServerKeyExchange();
            if (serverKeyExchange != null)
            {
                handshake.SendMessage(HandshakeType.server_key_exchange, serverKeyExchange);
            }

            if (state.serverCredentials != null)
            {
                state.certificateRequest = state.server.GetCertificateRequest();
                if (state.certificateRequest != null)
                {
                    if (TlsUtilities.IsTlsV12(state.serverContext) != (state.certificateRequest.SupportedSignatureAlgorithms != null))
                    {
                        throw new TlsFatalAlert(AlertDescription.internal_error);
                    }

                    state.keyExchange.ValidateCertificateRequest(state.certificateRequest);

                    byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest);
                    handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody);

                    TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash,
                                                     state.certificateRequest.SupportedSignatureAlgorithms);
                }
            }

            handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes);

            handshake.HandshakeHash.SealHashAlgorithms();

            clientMessage = handshake.ReceiveMessage();

            if (clientMessage.Type == HandshakeType.supplemental_data)
            {
                ProcessClientSupplementalData(state, clientMessage.Body);
                clientMessage = handshake.ReceiveMessage();
            }
            else
            {
                state.server.ProcessClientSupplementalData(null);
            }

            if (state.certificateRequest == null)
            {
                state.keyExchange.SkipClientCredentials();
            }
            else
            {
                if (clientMessage.Type == HandshakeType.certificate)
                {
                    ProcessClientCertificate(state, clientMessage.Body);
                    clientMessage = handshake.ReceiveMessage();
                }
                else
                {
                    if (TlsUtilities.IsTlsV12(state.serverContext))
                    {
                        /*
                         * RFC 5246 If no suitable certificate is available, the client MUST send a
                         * certificate message containing no certificates.
                         *
                         * NOTE: In previous RFCs, this was SHOULD instead of MUST.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    NotifyClientCertificate(state, Certificate.EmptyChain);
                }
            }

            if (clientMessage.Type == HandshakeType.client_key_exchange)
            {
                ProcessClientKeyExchange(state, clientMessage.Body);
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }

            TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish();

            securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.serverContext, prepareFinishHash, null);

            TlsProtocol.EstablishMasterSecret(state.serverContext, state.keyExchange);
            recordLayer.InitPendingEpoch(state.server.GetCipher());

            /*
             * RFC 5246 7.4.8 This message is only sent following a client certificate that has signing
             * capability (i.e., all certificates except those containing fixed Diffie-Hellman
             * parameters).
             */
            if (ExpectCertificateVerifyMessage(state))
            {
                byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify);
                ProcessCertificateVerify(state, certificateVerifyBody, prepareFinishHash);
            }

            // NOTE: Calculated exclusive of the actual Finished message from the client
            byte[] expectedClientVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.client_finished,
                                                                               TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null));
            ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedClientVerifyData);

            if (state.expectSessionTicket)
            {
                NewSessionTicket newSessionTicket     = state.server.GetNewSessionTicket();
                byte[]           newSessionTicketBody = GenerateNewSessionTicket(state, newSessionTicket);
                handshake.SendMessage(HandshakeType.session_ticket, newSessionTicketBody);
            }

            // NOTE: Calculated exclusive of the Finished message itself
            byte[] serverVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.server_finished,
                                                                       TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null));
            handshake.SendMessage(HandshakeType.finished, serverVerifyData);

            handshake.Finish();

            //{
            //    state.sessionParameters = new SessionParameters.Builder()
            //        .SetCipherSuite(securityParameters.CipherSuite)
            //        .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm)
            //        .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret)
            //        .SetMasterSecret(securityParameters.MasterSecret)
            //        .SetPeerCertificate(state.clientCertificate)
            //        .SetPskIdentity(securityParameters.PskIdentity)
            //        .SetSrpIdentity(securityParameters.SrpIdentity)
            //        // TODO Consider filtering extensions that aren't relevant to resumed sessions
            //        .SetServerExtensions(state.serverExtensions)
            //        .Build();

            //    state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters);

            //    state.serverContext.SetResumableSession(state.tlsSession);
            //}

            state.server.NotifyHandshakeComplete();

            return(new DtlsTransport(recordLayer));
        }
        public virtual void Init(TlsContext context)
        {
            this.mContext = context;

            ProtocolVersion clientVersion = context.ClientVersion;

            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
            {
                /*
                 * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension,
                 * the server MUST do the following:
                 *
                 * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK,
                 * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}.
                 *
                 * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if
                 * the client had sent the value {sha1,dsa}.
                 *
                 * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA),
                 * behave as if the client had sent value {sha1,ecdsa}.
                 */
                if (this.mSupportedSignatureAlgorithms == null)
                {
                    switch (mKeyExchange)
                    {
                    case KeyExchangeAlgorithm.DH_DSS:
                    case KeyExchangeAlgorithm.DHE_DSS:
                    case KeyExchangeAlgorithm.SRP_DSS:
                    {
                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultDssSignatureAlgorithms();
                        break;
                    }

                    case KeyExchangeAlgorithm.ECDH_ECDSA:
                    case KeyExchangeAlgorithm.ECDHE_ECDSA:
                    {
                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
                        break;
                    }

                    case KeyExchangeAlgorithm.DH_RSA:
                    case KeyExchangeAlgorithm.DHE_RSA:
                    case KeyExchangeAlgorithm.ECDH_RSA:
                    case KeyExchangeAlgorithm.ECDHE_RSA:
                    case KeyExchangeAlgorithm.RSA:
                    case KeyExchangeAlgorithm.RSA_PSK:
                    case KeyExchangeAlgorithm.SRP_RSA:
                    {
                        this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
                        break;
                    }

                    case KeyExchangeAlgorithm.DHE_PSK:
                    case KeyExchangeAlgorithm.ECDHE_PSK:
                    case KeyExchangeAlgorithm.PSK:
                    case KeyExchangeAlgorithm.SRP:
                        break;

                    default:
                        throw new InvalidOperationException("unsupported key exchange algorithm");
                    }
                }
            }
            else if (this.mSupportedSignatureAlgorithms != null)
            {
                throw new InvalidOperationException("supported_signature_algorithms not allowed for " + clientVersion);
            }
        }
Esempio n. 23
0
        protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
        {
            switch (type)
            {
            case HandshakeType.client_hello:
            {
                switch (this.mConnectionState)
                {
                case CS_START:
                {
                    ReceiveClientHelloMessage(buf);
                    this.mConnectionState = CS_CLIENT_HELLO;

                    SendServerHelloMessage();
                    this.mConnectionState = CS_SERVER_HELLO;

                    mRecordStream.NotifyHelloComplete();

                    IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
                    if (serverSupplementalData != null)
                    {
                        SendSupplementalDataMessage(serverSupplementalData);
                    }
                    this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;

                    this.mKeyExchange = mTlsServer.GetKeyExchange();
                    this.mKeyExchange.Init(Context);

                    this.mServerCredentials = mTlsServer.GetCredentials();

                    AbstractCertificate serverCertificate = null;

                    if (this.mServerCredentials == null)
                    {
                        this.mKeyExchange.SkipServerCredentials();
                    }
                    else
                    {
                        this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);

                        serverCertificate = this.mServerCredentials.Certificate;
                        SendCertificateMessage(serverCertificate);
                    }
                    this.mConnectionState = CS_SERVER_CERTIFICATE;

                    // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
                    if (serverCertificate == null || serverCertificate.IsEmpty)
                    {
                        this.mAllowCertificateStatus = false;
                    }

                    if (this.mAllowCertificateStatus)
                    {
                        CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
                        if (certificateStatus != null)
                        {
                            SendCertificateStatusMessage(certificateStatus);
                        }
                    }

                    this.mConnectionState = CS_CERTIFICATE_STATUS;

                    byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
                    if (serverKeyExchange != null)
                    {
                        SendServerKeyExchangeMessage(serverKeyExchange);
                    }
                    this.mConnectionState = CS_SERVER_KEY_EXCHANGE;

                    if (this.mServerCredentials != null)
                    {
                        this.mCertificateRequest = mTlsServer.GetCertificateRequest();
                        if (this.mCertificateRequest != null)
                        {
                            if (TlsUtilities.IsTlsV12(Context) != (mCertificateRequest.SupportedSignatureAlgorithms != null))
                            {
                                throw new TlsFatalAlert(AlertDescription.internal_error);
                            }

                            this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);

                            SendCertificateRequestMessage(mCertificateRequest);

                            TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
                                                             this.mCertificateRequest.SupportedSignatureAlgorithms);
                        }
                    }
                    this.mConnectionState = CS_CERTIFICATE_REQUEST;

                    SendServerHelloDoneMessage();
                    this.mConnectionState = CS_SERVER_HELLO_DONE;

                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();

                    break;
                }

                case CS_END:
                {
                    RefuseRenegotiation();
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.supplemental_data:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                {
                    mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.certificate:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                case CS_CLIENT_SUPPLEMENTAL_DATA:
                {
                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }

                    if (this.mCertificateRequest == null)
                    {
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ReceiveCertificateMessage(buf);
                    this.mConnectionState = CS_CLIENT_CERTIFICATE;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.client_key_exchange:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO_DONE:
                case CS_CLIENT_SUPPLEMENTAL_DATA:
                case CS_CLIENT_CERTIFICATE:
                {
                    if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
                    {
                        mTlsServer.ProcessClientSupplementalData(null);
                    }

                    if (mConnectionState < CS_CLIENT_CERTIFICATE)
                    {
                        if (this.mCertificateRequest == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();
                        }
                        else
                        {
                            if (TlsUtilities.IsTlsV12(Context))
                            {
                                /*
                                 * RFC 5246 If no suitable certificate is available, the client MUST Send a
                                 * certificate message containing no certificates.
                                 *
                                 * NOTE: In previous RFCs, this was SHOULD instead of MUST.
                                 */
                                throw new TlsFatalAlert(AlertDescription.unexpected_message);
                            }
                            else if (TlsUtilities.IsSsl(Context))
                            {
                                if (this.mPeerCertificate == null)
                                {
                                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                                }
                            }
                            else
                            {
                                NotifyClientCertificate(Certificate.EmptyChain);
                            }
                        }
                    }

                    ReceiveClientKeyExchangeMessage(buf);
                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.certificate_verify:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_KEY_EXCHANGE:
                {
                    /*
                     * RFC 5246 7.4.8 This message is only sent following a client certificate that has
                     * signing capability (i.e., all certificates except those containing fixed
                     * Diffie-Hellman parameters).
                     */
                    if (!ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ReceiveCertificateVerifyMessage(buf);
                    this.mConnectionState = CS_CERTIFICATE_VERIFY;

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.finished:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_KEY_EXCHANGE:
                case CS_CERTIFICATE_VERIFY:
                {
                    if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
                    {
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ProcessFinishedMessage(buf);
                    this.mConnectionState = CS_CLIENT_FINISHED;

                    if (this.mExpectSessionTicket)
                    {
                        SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
                    }
                    this.mConnectionState = CS_SERVER_SESSION_TICKET;

                    SendChangeCipherSpecMessage();
                    SendFinishedMessage();
                    this.mConnectionState = CS_SERVER_FINISHED;

                    CompleteHandshake();
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.hello_request:
            case HandshakeType.hello_verify_request:
            case HandshakeType.server_hello:
            case HandshakeType.server_key_exchange:
            case HandshakeType.certificate_request:
            case HandshakeType.server_hello_done:
            case HandshakeType.session_ticket:
            default:
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }
        }
Esempio n. 24
0
        private bool ProcessRecord(int windowSize, int epoch, byte[] buf, int off, int len)
        {
            bool checkPreviousFlight = false;

            while (len >= MessageHeaderLength)
            {
                int fragment_length = TlsUtilities.ReadUint24(buf, off + 9);
                int message_length  = fragment_length + MessageHeaderLength;
                if (len < message_length)
                {
                    // NOTE: Truncated message - ignore it
                    break;
                }

                int length          = TlsUtilities.ReadUint24(buf, off + 1);
                int fragment_offset = TlsUtilities.ReadUint24(buf, off + 6);
                if (fragment_offset + fragment_length > length)
                {
                    // NOTE: Malformed fragment - ignore it and the rest of the record
                    break;
                }

                /*
                 * NOTE: This very simple epoch check will only work until we want to support
                 * renegotiation (and we're not likely to do that anyway).
                 */
                byte msg_type      = TlsUtilities.ReadUint8(buf, off + 0);
                int  expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0;
                if (epoch != expectedEpoch)
                {
                    break;
                }

                int message_seq = TlsUtilities.ReadUint16(buf, off + 4);
                if (message_seq >= (mNextReceiveSeq + windowSize))
                {
                    // NOTE: Too far ahead - ignore
                }
                else if (message_seq >= mNextReceiveSeq)
                {
                    DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[message_seq];
                    if (reassembler == null)
                    {
                        reassembler = new DtlsReassembler(msg_type, length);
                        mCurrentInboundFlight[message_seq] = reassembler;
                    }

                    reassembler.ContributeFragment(msg_type, length, buf, off + MessageHeaderLength, fragment_offset,
                                                   fragment_length);
                }
                else if (mPreviousInboundFlight != null)
                {
                    /*
                     * NOTE: If we receive the previous flight of incoming messages in full again,
                     * retransmit our last flight
                     */

                    DtlsReassembler reassembler = (DtlsReassembler)mPreviousInboundFlight[message_seq];
                    if (reassembler != null)
                    {
                        reassembler.ContributeFragment(msg_type, length, buf, off + MessageHeaderLength, fragment_offset,
                                                       fragment_length);
                        checkPreviousFlight = true;
                    }
                }

                off += message_length;
                len -= message_length;
            }

            bool result = checkPreviousFlight && CheckAll(mPreviousInboundFlight);

            if (result)
            {
                ResendOutboundFlight();
                ResetAll(mPreviousInboundFlight);
            }
            return(result);
        }
Esempio n. 25
0
        protected virtual void SendServerHelloMessage()
        {
            HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);

            {
                ProtocolVersion server_version = mTlsServer.GetServerVersion();
                if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                mRecordStream.ReadVersion = server_version;
                mRecordStream.SetWriteVersion(server_version);
                mRecordStream.SetRestrictReadVersion(true);
                ContextAdmin.SetServerVersion(server_version);

                TlsUtilities.WriteVersion(server_version, message);
            }

            message.Write(this.mSecurityParameters.serverRandom);

            /*
             * The server may return an empty session_id to indicate that the session will not be cached
             * and therefore cannot be resumed.
             */
            TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);

            int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();

            if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite) ||
                selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL ||
                CipherSuite.IsScsv(selectedCipherSuite) ||
                !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            mSecurityParameters.cipherSuite = selectedCipherSuite;

            byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();

            if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
            mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;

            TlsUtilities.WriteUint16(selectedCipherSuite, message);
            TlsUtilities.WriteUint8(selectedCompressionMethod, message);

            this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsServer.GetServerExtensions());

            /*
             * RFC 5746 3.6. Server Behavior: Initial Handshake
             */
            if (this.mSecureRenegotiation)
            {
                byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
                bool   noRenegExt   = (null == renegExtData);

                if (noRenegExt)
                {
                    /*
                     * Note that Sending a "renegotiation_info" extension in response to a ClientHello
                     * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
                     * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed
                     * because the client is signaling its willingness to receive the extension via the
                     * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
                     */

                    /*
                     * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
                     * "renegotiation_info" extension in the ServerHello message.
                     */
                    this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
                }
            }

            if (TlsUtilities.IsSsl(mTlsServerContext))
            {
                mSecurityParameters.extendedMasterSecret = false;
            }
            else if (mSecurityParameters.IsExtendedMasterSecret)
            {
                TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
            }

            /*
             * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
             * extensions appearing in the client hello, and Send a server hello containing no
             * extensions.
             */

            if (this.mServerExtensions.Count > 0)
            {
                this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);

                this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
                                                                                               mServerExtensions, AlertDescription.internal_error);

                this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);

                /*
                 * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
                 * a session resumption handshake.
                 */
                this.mAllowCertificateStatus = !mResumedSession &&
                                               TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
                                                                                          AlertDescription.internal_error);

                this.mExpectSessionTicket = !mResumedSession &&
                                            TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
                                                                                       AlertDescription.internal_error);

                ProcessCertificateFormats();

                /*
                 *
                 */

                WriteExtensions(message, this.mServerExtensions);
            }

            mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);

            /*
             * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
             * a verify_data_length equal to 12. This includes all existing cipher suites.
             */
            mSecurityParameters.verifyDataLength = 12;

            ApplyMaxFragmentLengthExtension();

            message.WriteToRecordStream(this);
        }
Esempio n. 26
0
        private void processHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of
                 * the message.
                 */
                if (handshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    handshakeQueue.Read(beginning, 0, 4, 0);
                    MemoryStream bis  = new MemoryStream(beginning, false);
                    short        type = TlsUtilities.ReadUint8(bis);
                    int          len  = TlsUtilities.ReadUint24(bis);

                    /*
                     * Check if we have enough bytes in the buffer to read
                     * the full message.
                     */
                    if (handshakeQueue.Available >= (len + 4))
                    {
                        /*
                         * Read the message.
                         */
                        byte[] buf = new byte[len];
                        handshakeQueue.Read(buf, 0, len, 4);
                        handshakeQueue.RemoveData(len + 4);

                        /*
                         * If it is not a finished message, update our hashes
                         * we prepare for the finish message.
                         */
                        if (type != HP_FINISHED)
                        {
                            rs.hash1.BlockUpdate(beginning, 0, 4);
                            rs.hash2.BlockUpdate(beginning, 0, 4);
                            rs.hash1.BlockUpdate(buf, 0, len);
                            rs.hash2.BlockUpdate(buf, 0, len);
                        }

                        /*
                         * Now, parse the message.
                         */
                        MemoryStream inStr = new MemoryStream(buf, false);

                        /*
                         * Check the type.
                         */
                        switch (type)
                        {
                        case HP_CERTIFICATE:
                        {
                            switch (connection_state)
                            {
                            case CS_SERVER_HELLO_RECEIVED:
                            {
                                /*
                                 * Parse the certificates.
                                 */
                                Certificate cert = Certificate.Parse(inStr);
                                AssertEmpty(inStr);

                                X509CertificateStructure x509Cert = cert.certs[0];
                                SubjectPublicKeyInfo     keyInfo  = x509Cert.SubjectPublicKeyInfo;

                                try
                                {
                                    this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo);
                                }
                                catch (Exception)
                                {
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                }

                                // Sanity check the PublicKeyFactory
                                if (this.serverPublicKey.IsPrivate)
                                {
                                    this.FailWithError(AL_fatal, AP_internal_error);
                                }

                                /*
                                 * Perform various checks per RFC2246 7.4.2
                                 * TODO "Unless otherwise specified, the signing algorithm for the certificate
                                 * must be the same as the algorithm for the certificate key."
                                 */
                                switch (this.chosenCipherSuite.KeyExchangeAlgorithm)
                                {
                                case TlsCipherSuite.KE_RSA:
                                    if (!(this.serverPublicKey is RsaKeyParameters))
                                    {
                                        this.FailWithError(AL_fatal, AP_certificate_unknown);
                                    }
                                    validateKeyUsage(x509Cert, KeyUsage.KeyEncipherment);
                                    break;

                                case TlsCipherSuite.KE_DHE_RSA:
                                    if (!(this.serverPublicKey is RsaKeyParameters))
                                    {
                                        this.FailWithError(AL_fatal, AP_certificate_unknown);
                                    }
                                    validateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
                                    break;

                                case TlsCipherSuite.KE_DHE_DSS:
                                    if (!(this.serverPublicKey is DsaPublicKeyParameters))
                                    {
                                        this.FailWithError(AL_fatal, AP_certificate_unknown);
                                    }
                                    break;

                                default:
                                    this.FailWithError(AL_fatal, AP_unsupported_certificate);
                                    break;
                                }

                                /*
                                 * Verify them.
                                 */
                                if (!this.verifyer.IsValid(cert.GetCerts()))
                                {
                                    this.FailWithError(AL_fatal, AP_user_canceled);
                                }

                                break;
                            }

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }

                            connection_state = CS_SERVER_CERTIFICATE_RECEIVED;
                            read             = true;
                            break;
                        }

                        case HP_FINISHED:
                            switch (connection_state)
                            {
                            case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED:
                                /*
                                 * Read the checksum from the finished message,
                                 * it has always 12 bytes.
                                 */
                                byte[] receivedChecksum = new byte[12];
                                TlsUtilities.ReadFully(receivedChecksum, inStr);
                                AssertEmpty(inStr);

                                /*
                                 * Calculate our own checksum.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash2.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum);

                                /*
                                 * Compare both checksums.
                                 */
                                for (int i = 0; i < receivedChecksum.Length; i++)
                                {
                                    if (receivedChecksum[i] != checksum[i])
                                    {
                                        /*
                                         * Wrong checksum in the finished message.
                                         */
                                        this.FailWithError(AL_fatal, AP_handshake_failure);
                                    }
                                }

                                connection_state = CS_DONE;

                                /*
                                 * We are now ready to receive application data.
                                 */
                                this.appDataReady = true;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO:
                            switch (connection_state)
                            {
                            case CS_CLIENT_HELLO_SEND:
                                /*
                                 * Read the server hello message
                                 */
                                TlsUtilities.CheckVersion(inStr, this);

                                /*
                                 * Read the server random
                                 */
                                this.serverRandom = new byte[32];
                                TlsUtilities.ReadFully(this.serverRandom, inStr);

                                /*
                                 * Currently, we don't support session ids
                                 */
                                short  sessionIdLength = TlsUtilities.ReadUint8(inStr);
                                byte[] sessionId       = new byte[sessionIdLength];
                                TlsUtilities.ReadFully(sessionId, inStr);

                                /*
                                 * Find out which ciphersuite the server has
                                 * chosen. If we don't support this ciphersuite,
                                 * the TlsCipherSuiteManager will throw an
                                 * exception.
                                 */
                                this.chosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite(
                                    TlsUtilities.ReadUint16(inStr), this);

                                /*
                                 * We support only the null compression which
                                 * means no compression.
                                 */
                                short compressionMethod = TlsUtilities.ReadUint8(inStr);
                                if (compressionMethod != 0)
                                {
                                    this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter);
                                }
                                AssertEmpty(inStr);

                                connection_state = CS_SERVER_HELLO_RECEIVED;
                                read             = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }
                            break;

                        case HP_SERVER_HELLO_DONE:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:
                            case CS_CERTIFICATE_REQUEST_RECEIVED:

                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                AssertEmpty(inStr);
                                bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED);
                                connection_state = CS_SERVER_HELLO_DONE_RECEIVED;

                                if (isCertReq)
                                {
                                    sendClientCertificate();
                                }

                                /*
                                 * Send the client key exchange message, depending
                                 * on the key exchange we are using in our
                                 * ciphersuite.
                                 */
                                switch (this.chosenCipherSuite.KeyExchangeAlgorithm)
                                {
                                case TlsCipherSuite.KE_RSA:
                                {
                                    /*
                                     * We are doing RSA key exchange. We will
                                     * choose a pre master secret and send it
                                     * rsa encrypted to the server.
                                     *
                                     * Prepare pre master secret.
                                     */
                                    pms    = new byte[48];
                                    pms[0] = 3;
                                    pms[1] = 1;
                                    random.NextBytes(pms, 2, 46);

                                    /*
                                     * Encode the pms and send it to the server.
                                     *
                                     * Prepare an Pkcs1Encoding with good random
                                     * padding.
                                     */
                                    RsaBlindedEngine rsa      = new RsaBlindedEngine();
                                    Pkcs1Encoding    encoding = new Pkcs1Encoding(rsa);
                                    encoding.Init(true, new ParametersWithRandom(this.serverPublicKey, this.random));
                                    byte[] encrypted = null;
                                    try
                                    {
                                        encrypted = encoding.ProcessBlock(pms, 0, pms.Length);
                                    }
                                    catch (InvalidCipherTextException)
                                    {
                                        /*
                                         * This should never happen, only during decryption.
                                         */
                                        this.FailWithError(AL_fatal, AP_internal_error);
                                    }

                                    /*
                                     * Send the encrypted pms.
                                     */
                                    sendClientKeyExchange(encrypted);
                                    break;
                                }

                                case TlsCipherSuite.KE_DHE_DSS:
                                case TlsCipherSuite.KE_DHE_RSA:
                                {
                                    /*
                                     * Send the Client Key Exchange message for
                                     * DHE key exchange.
                                     */
                                    byte[] YcByte = BigIntegers.AsUnsignedByteArray(this.Yc);

                                    sendClientKeyExchange(YcByte);

                                    break;
                                }

                                default:
                                    /*
                                     * Problem during handshake, we don't know
                                     * how to handle this key exchange method.
                                     */
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                    break;
                                }

                                connection_state = CS_CLIENT_KEY_EXCHANGE_SEND;

                                /*
                                 * Now, we send change cipher state
                                 */
                                byte[] cmessage = new byte[1];
                                cmessage[0] = 1;
                                rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length);

                                connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND;

                                /*
                                 * Calculate the ms
                                 */
                                this.ms = new byte[48];
                                byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length];
                                Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length);
                                Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length);
                                TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms);

                                /*
                                 * Initialize our cipher suite
                                 */
                                rs.writeSuite = this.chosenCipherSuite;
                                rs.writeSuite.Init(this.ms, clientRandom, serverRandom);

                                /*
                                 * Send our finished message.
                                 */
                                byte[] checksum   = new byte[12];
                                byte[] md5andsha1 = new byte[16 + 20];
                                rs.hash1.DoFinal(md5andsha1, 0);
                                TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum);

                                MemoryStream bos2 = new MemoryStream();
                                TlsUtilities.WriteUint8(HP_FINISHED, bos2);
                                TlsUtilities.WriteUint24(12, bos2);
                                bos2.Write(checksum, 0, checksum.Length);
                                byte[] message2 = bos2.ToArray();

                                rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length);

                                this.connection_state = CS_CLIENT_FINISHED_SEND;
                                read = true;
                                break;

                            default:
                                this.FailWithError(AL_fatal, AP_handshake_failure);
                                break;
                            }
                            break;

                        case HP_SERVER_KEY_EXCHANGE:
                        {
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            {
                                /*
                                 * Check that we are doing DHE key exchange
                                 */
                                switch (this.chosenCipherSuite.KeyExchangeAlgorithm)
                                {
                                case TlsCipherSuite.KE_DHE_RSA:
                                {
                                    processDHEKeyExchange(inStr, new TlsRsaSigner());
                                    break;
                                }

                                case TlsCipherSuite.KE_DHE_DSS:
                                {
                                    processDHEKeyExchange(inStr, new TlsDssSigner());
                                    break;
                                }

                                default:
                                    this.FailWithError(AL_fatal, AP_unexpected_message);
                                    break;
                                }
                                break;
                            }

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }

                            this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED;
                            read = true;
                            break;
                        }

                        case HP_CERTIFICATE_REQUEST:
                            switch (connection_state)
                            {
                            case CS_SERVER_CERTIFICATE_RECEIVED:
                            case CS_SERVER_KEY_EXCHANGE_RECEIVED:
                            {
                                // NB: Original code used case label fall-through
                                if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED)
                                {
                                    /*
                                     * There was no server key exchange message, check
                                     * that we are doing RSA key exchange.
                                     */
                                    if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA)
                                    {
                                        this.FailWithError(AL_fatal, AP_unexpected_message);
                                    }
                                }

                                int    typesLength = TlsUtilities.ReadUint8(inStr);
                                byte[] types       = new byte[typesLength];
                                TlsUtilities.ReadFully(types, inStr);

                                int    authsLength = TlsUtilities.ReadUint16(inStr);
                                byte[] auths       = new byte[authsLength];
                                TlsUtilities.ReadFully(auths, inStr);

                                AssertEmpty(inStr);
                                break;
                            }

                            default:
                                this.FailWithError(AL_fatal, AP_unexpected_message);
                                break;
                            }

                            this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED;
                            read = true;
                            break;

                        case HP_HELLO_REQUEST:
                        case HP_CLIENT_KEY_EXCHANGE:
                        case HP_CERTIFICATE_VERIFY:
                        case HP_CLIENT_HELLO:
                        default:
                            // We do not support this!
                            this.FailWithError(AL_fatal, AP_unexpected_message);
                            break;
                        }
                    }
                }
            }while (read);
        }
Esempio n. 27
0
        private void ProcessHandshake()
        {
            bool read;

            do
            {
                read = false;

                /*
                 * We need the first 4 bytes, they contain type and length of the message.
                 */
                if (mHandshakeQueue.Available >= 4)
                {
                    byte[] beginning = new byte[4];
                    mHandshakeQueue.Read(beginning, 0, 4, 0);
                    byte type = TlsUtilities.ReadUint8(beginning, 0);
                    int  len  = TlsUtilities.ReadUint24(beginning, 1);

                    /*
                     * Check if we have enough bytes in the buffer to read the full message.
                     */
                    if (mHandshakeQueue.Available >= (len + 4))
                    {
                        /*
                         * Read the message.
                         */
                        byte[] buf = mHandshakeQueue.RemoveData(len, 4);

                        CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished);

                        /*
                         * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages
                         * starting at client hello up to, but not including, this finished message.
                         * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes.
                         */
                        switch (type)
                        {
                        case HandshakeType.hello_request:
                            break;

                        case HandshakeType.finished:
                        default:
                        {
                            TlsContext ctx = Context;
                            if (type == HandshakeType.finished &&
                                this.mExpectedVerifyData == null &&
                                ctx.SecurityParameters.MasterSecret != null)
                            {
                                this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer);
                            }

                            mRecordStream.UpdateHandshakeData(beginning, 0, 4);
                            mRecordStream.UpdateHandshakeData(buf, 0, len);
                            break;
                        }
                        }

                        /*
                         * Now, parse the message.
                         */
                        HandleHandshakeMessage(type, buf);
                        read = true;
                    }
                }
            }while (read);
        }
Esempio n. 28
0
        private void processDHEKeyExchange(
            MemoryStream inStr,
            ISigner signer)
        {
            Stream sigIn = inStr;

            if (signer != null)
            {
                signer.Init(false, this.serverPublicKey);
                signer.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length);
                signer.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length);

                sigIn = new SignerStream(inStr, signer, null);
            }

            /*
             * Parse the Structure
             */
            int pLength = TlsUtilities.ReadUint16(sigIn);

            byte[] pByte = new byte[pLength];
            TlsUtilities.ReadFully(pByte, sigIn);

            int gLength = TlsUtilities.ReadUint16(sigIn);

            byte[] gByte = new byte[gLength];
            TlsUtilities.ReadFully(gByte, sigIn);

            int YsLength = TlsUtilities.ReadUint16(sigIn);

            byte[] YsByte = new byte[YsLength];
            TlsUtilities.ReadFully(YsByte, sigIn);

            if (signer != null)
            {
                int    sigLength = TlsUtilities.ReadUint16(inStr);
                byte[] sigByte   = new byte[sigLength];
                TlsUtilities.ReadFully(sigByte, inStr);

                /*
                 * Verify the Signature.
                 */
                if (!signer.VerifySignature(sigByte))
                {
                    this.FailWithError(AL_fatal, AP_bad_certificate);
                }
            }

            this.AssertEmpty(inStr);

            /*
             * Do the DH calculation.
             */
            BigInteger p  = new BigInteger(1, pByte);
            BigInteger g  = new BigInteger(1, gByte);
            BigInteger Ys = new BigInteger(1, YsByte);

            /*
             * Check the DH parameter values
             */
            if (!p.IsProbablePrime(10))
            {
                this.FailWithError(AL_fatal, AP_illegal_parameter);
            }
            if (g.CompareTo(BigInteger.Two) < 0 || g.CompareTo(p.Subtract(BigInteger.Two)) > 0)
            {
                this.FailWithError(AL_fatal, AP_illegal_parameter);
            }
            // TODO For static DH public values, see additional checks in RFC 2631 2.1.5
            if (Ys.CompareTo(BigInteger.Two) < 0 || Ys.CompareTo(p.Subtract(BigInteger.One)) > 0)
            {
                this.FailWithError(AL_fatal, AP_illegal_parameter);
            }

            /*
             * Diffie-Hellman basic key agreement
             */
            DHParameters dhParams = new DHParameters(p, g);

            // Generate a keypair
            DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator();

            dhGen.Init(new DHKeyGenerationParameters(random, dhParams));

            AsymmetricCipherKeyPair dhPair = dhGen.GenerateKeyPair();

            // Store the public value to send to server
            this.Yc = ((DHPublicKeyParameters)dhPair.Public).Y;

            // Calculate the shared secret
            DHBasicAgreement dhAgree = new DHBasicAgreement();

            dhAgree.Init(dhPair.Private);

            BigInteger agreement = dhAgree.CalculateAgreement(new DHPublicKeyParameters(Ys, dhParams));

            this.pms = BigIntegers.AsUnsignedByteArray(agreement);
        }
Esempio n. 29
0
        protected internal static int GetPrfAlgorithm(TlsContext context, int ciphersuite)
        {
            bool isTLSv12 = TlsUtilities.IsTlsV12(context);

            switch (ciphersuite)
            {
            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
            {
                if (isTLSv12)
                {
                    return(PrfAlgorithm.tls_prf_sha256);
                }
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
            {
                if (isTLSv12)
                {
                    return(PrfAlgorithm.tls_prf_sha384);
                }
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }

            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
            {
                if (isTLSv12)
                {
                    return(PrfAlgorithm.tls_prf_sha384);
                }
                return(PrfAlgorithm.tls_prf_legacy);
            }

            default:
            {
                if (isTLSv12)
                {
                    return(PrfAlgorithm.tls_prf_sha256);
                }
                return(PrfAlgorithm.tls_prf_legacy);
            }
            }
        }
Esempio n. 30
0
        protected override void HandleHandshakeMessage(byte type, byte[] data)
        {
            MemoryStream buf = new MemoryStream(data, false);

            if (this.mResumedSession)
            {
                if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
                {
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                ProcessFinishedMessage(buf);
                this.mConnectionState = CS_SERVER_FINISHED;

                SendFinishedMessage();
                this.mConnectionState = CS_CLIENT_FINISHED;
                this.mConnectionState = CS_END;

                return;
            }

            switch (type)
            {
            case HandshakeType.certificate:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                case CS_SERVER_SUPPLEMENTAL_DATA:
                {
                    if (this.mConnectionState == CS_SERVER_HELLO)
                    {
                        HandleSupplementalData(null);
                    }

                    // Parse the Certificate message and Send to cipher suite

                    this.mPeerCertificate = Certificate.Parse(buf);

                    AssertEmpty(buf);

                    // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
                    if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
                    {
                        this.mAllowCertificateStatus = false;
                    }

                    this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);

                    this.mAuthentication = mTlsClient.GetAuthentication();
                    this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_SERVER_CERTIFICATE;
                break;
            }

            case HandshakeType.certificate_status:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_CERTIFICATE:
                {
                    if (!this.mAllowCertificateStatus)
                    {
                        /*
                         * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
                         * server MUST have included an extension of type "status_request" with empty
                         * "extension_data" in the extended server hello..
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    this.mCertificateStatus = CertificateStatus.Parse(buf);

                    AssertEmpty(buf);

                    // TODO[RFC 3546] Figure out how to provide this to the client/authentication.

                    this.mConnectionState = CS_CERTIFICATE_STATUS;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.finished:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_FINISHED:
                case CS_SERVER_SESSION_TICKET:
                {
                    if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
                    {
                        /*
                         * RFC 5077 3.3. This message MUST be sent if the server included a
                         * SessionTicket extension in the ServerHello.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    ProcessFinishedMessage(buf);
                    this.mConnectionState = CS_SERVER_FINISHED;
                    this.mConnectionState = CS_END;
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.server_hello:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_HELLO:
                {
                    ReceiveServerHelloMessage(buf);
                    this.mConnectionState = CS_SERVER_HELLO;

                    this.mRecordStream.NotifyHelloComplete();

                    ApplyMaxFragmentLengthExtension();

                    if (this.mResumedSession)
                    {
                        this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
                        this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());

                        SendChangeCipherSpecMessage();
                    }
                    else
                    {
                        InvalidateSession();

                        if (this.mSelectedSessionID.Length > 0)
                        {
                            this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
                        }
                    }

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.supplemental_data:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                {
                    HandleSupplementalData(ReadSupplementalDataMessage(buf));
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }
                break;
            }

            case HandshakeType.server_hello_done:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                case CS_SERVER_SUPPLEMENTAL_DATA:
                case CS_SERVER_CERTIFICATE:
                case CS_CERTIFICATE_STATUS:
                case CS_SERVER_KEY_EXCHANGE:
                case CS_CERTIFICATE_REQUEST:
                {
                    if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
                    {
                        HandleSupplementalData(null);
                    }

                    if (mConnectionState < CS_SERVER_CERTIFICATE)
                    {
                        // There was no server certificate message; check it's OK
                        this.mKeyExchange.SkipServerCredentials();
                        this.mAuthentication = null;
                    }

                    if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
                    {
                        // There was no server key exchange message; check it's OK
                        this.mKeyExchange.SkipServerKeyExchange();
                    }

                    AssertEmpty(buf);

                    this.mConnectionState = CS_SERVER_HELLO_DONE;

                    this.mRecordStream.HandshakeHash.SealHashAlgorithms();

                    IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
                    if (clientSupplementalData != null)
                    {
                        SendSupplementalDataMessage(clientSupplementalData);
                    }
                    this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;

                    TlsCredentials clientCreds = null;
                    if (mCertificateRequest == null)
                    {
                        this.mKeyExchange.SkipClientCredentials();
                    }
                    else
                    {
                        clientCreds = this.mAuthentication.GetClientCredentials(mCertificateRequest);

                        if (clientCreds == null)
                        {
                            this.mKeyExchange.SkipClientCredentials();

                            /*
                             * RFC 5246 If no suitable certificate is available, the client MUST Send a
                             * certificate message containing no certificates.
                             *
                             * NOTE: In previous RFCs, this was SHOULD instead of MUST.
                             */
                            SendCertificateMessage(Certificate.EmptyChain);
                        }
                        else
                        {
                            this.mKeyExchange.ProcessClientCredentials(clientCreds);

                            SendCertificateMessage(clientCreds.Certificate);
                        }
                    }

                    this.mConnectionState = CS_CLIENT_CERTIFICATE;

                    /*
                     * Send the client key exchange message, depending on the key exchange we are using
                     * in our CipherSuite.
                     */
                    SendClientKeyExchangeMessage();
                    this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;

                    TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
                    this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);

                    EstablishMasterSecret(Context, mKeyExchange);
                    mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());

                    if (clientCreds != null && clientCreds is TlsSignerCredentials)
                    {
                        TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;

                        /*
                         * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
                         */
                        SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
                            Context, signerCredentials);

                        byte[] hash;
                        if (signatureAndHashAlgorithm == null)
                        {
                            hash = mSecurityParameters.SessionHash;
                        }
                        else
                        {
                            hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
                        }

                        byte[]          signature         = signerCredentials.GenerateCertificateSignature(hash);
                        DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
                        SendCertificateVerifyMessage(certificateVerify);

                        this.mConnectionState = CS_CERTIFICATE_VERIFY;
                    }

                    SendChangeCipherSpecMessage();
                    SendFinishedMessage();
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.handshake_failure);
                }

                this.mConnectionState = CS_CLIENT_FINISHED;
                break;
            }

            case HandshakeType.server_key_exchange:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_HELLO:
                case CS_SERVER_SUPPLEMENTAL_DATA:
                case CS_SERVER_CERTIFICATE:
                case CS_CERTIFICATE_STATUS:
                {
                    if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
                    {
                        HandleSupplementalData(null);
                    }

                    if (mConnectionState < CS_SERVER_CERTIFICATE)
                    {
                        // There was no server certificate message; check it's OK
                        this.mKeyExchange.SkipServerCredentials();
                        this.mAuthentication = null;
                    }

                    this.mKeyExchange.ProcessServerKeyExchange(buf);

                    AssertEmpty(buf);
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
                break;
            }

            case HandshakeType.certificate_request:
            {
                switch (this.mConnectionState)
                {
                case CS_SERVER_CERTIFICATE:
                case CS_CERTIFICATE_STATUS:
                case CS_SERVER_KEY_EXCHANGE:
                {
                    if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
                    {
                        // There was no server key exchange message; check it's OK
                        this.mKeyExchange.SkipServerKeyExchange();
                    }

                    if (this.mAuthentication == null)
                    {
                        /*
                         * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
                         * to request client identification.
                         */
                        throw new TlsFatalAlert(AlertDescription.handshake_failure);
                    }

                    this.mCertificateRequest = CertificateRequest.Parse(Context, buf);

                    AssertEmpty(buf);

                    this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);

                    /*
                     * TODO Give the client a chance to immediately select the CertificateVerify hash
                     * algorithm here to avoid tracking the other hash algorithms unnecessarily?
                     */
                    TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
                                                     this.mCertificateRequest.SupportedSignatureAlgorithms);

                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_CERTIFICATE_REQUEST;
                break;
            }

            case HandshakeType.session_ticket:
            {
                switch (this.mConnectionState)
                {
                case CS_CLIENT_FINISHED:
                {
                    if (!this.mExpectSessionTicket)
                    {
                        /*
                         * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
                         * SessionTicket extension in the ServerHello.
                         */
                        throw new TlsFatalAlert(AlertDescription.unexpected_message);
                    }

                    /*
                     * RFC 5077 3.4. If the client receives a session ticket from the server, then it
                     * discards any Session ID that was sent in the ServerHello.
                     */
                    InvalidateSession();

                    ReceiveNewSessionTicketMessage(buf);
                    break;
                }

                default:
                    throw new TlsFatalAlert(AlertDescription.unexpected_message);
                }

                this.mConnectionState = CS_SERVER_SESSION_TICKET;
                break;
            }

            case HandshakeType.hello_request:
            {
                AssertEmpty(buf);

                /*
                 * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
                 * client is currently negotiating a session. This message may be ignored by the client
                 * if it does not wish to renegotiate a session, or the client may, if it wishes,
                 * respond with a no_renegotiation alert.
                 */
                if (this.mConnectionState == CS_END)
                {
                    RefuseRenegotiation();
                }
                break;
            }

            case HandshakeType.client_hello:
            case HandshakeType.client_key_exchange:
            case HandshakeType.certificate_verify:
            case HandshakeType.hello_verify_request:
            default:
                throw new TlsFatalAlert(AlertDescription.unexpected_message);
            }
        }