public virtual int GetSelectedCipherSuite()
        {
            /*
             * TODO RFC 5246 7.4.3. In order to negotiate correctly, the server MUST check any candidate
             * cipher suites against the "signature_algorithms" extension before selecting them. This is
             * somewhat inelegant but is a compromise designed to minimize changes to the original
             * cipher suite design.
             */

            /*
             * RFC 4429 5.1. A server that receives a ClientHello containing one or both of these
             * extensions MUST use the client's enumerated capabilities to guide its selection of an
             * appropriate cipher suite. One of the proposed ECC cipher suites must be negotiated only
             * if the server can successfully complete the handshake while using the curves and point
             * formats supported by the client [...].
             */
            bool eccCipherSuitesEnabled = SupportsClientEccCapabilities(this.mNamedCurves, this.mClientECPointFormats);

            int[] cipherSuites = GetCipherSuites();
            for (int i = 0; i < cipherSuites.Length; ++i)
            {
                int cipherSuite = cipherSuites[i];

                if (Arrays.Contains(this.mOfferedCipherSuites, cipherSuite) &&
                    (eccCipherSuitesEnabled || !TlsEccUtilities.IsEccCipherSuite(cipherSuite)) &&
                    TlsUtilities.IsValidCipherSuiteForVersion(cipherSuite, mServerVersion))
                {
                    return(this.mSelectedCipherSuite = cipherSuite);
                }
            }
            throw new TlsFatalAlert(AlertDescription.handshake_failure);
        }
Example #2
0
        protected virtual byte[] GenerateOtherSecret(int pskLength)
        {
            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
            {
                if (mDHAgreePrivateKey != null)
                {
                    return(TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey));
                }

                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
            {
                if (mECAgreePrivateKey != null)
                {
                    return(TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey));
                }

                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
            {
                return(this.mPremasterSecret);
            }

            return(new byte[pskLength]);
        }
        protected virtual bool SupportsClientEccCapabilities(int[] namedCurves, byte[] ecPointFormats)
        {
            // NOTE: BC supports all the current set of point formats so we don't check them here

            if (namedCurves == null)
            {
                /*
                 * RFC 4492 4. A client that proposes ECC cipher suites may choose not to include these
                 * extensions. In this case, the server is free to choose any one of the elliptic curves
                 * or point formats [...].
                 */
                return(TlsEccUtilities.HasAnySupportedNamedCurves());
            }

            for (int i = 0; i < namedCurves.Length; ++i)
            {
                int namedCurve = namedCurves[i];
                if (NamedCurve.IsValid(namedCurve) &&
                    (!NamedCurve.RefersToASpecificNamedCurve(namedCurve) || TlsEccUtilities.IsSupportedNamedCurve(namedCurve)))
                {
                    return(true);
                }
            }

            return(false);
        }
        public override byte[] GenerateServerKeyExchange()
        {
            DigestInputBuffer buf = new DigestInputBuffer();

            this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
                                                                                         mClientECPointFormats, buf);

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

            IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm);

            SecurityParameters securityParameters = mContext.SecurityParameters;

            d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
            d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
            buf.UpdateDigest(d);

            byte[] hash = DigestUtilities.DoFinal(d);

            byte[] signature = mServerCredentials.GenerateCertificateSignature(hash);

            DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature);

            signed_params.Encode(buf);

            return(buf.ToArray());
        }
        public virtual void ProcessServerExtensions(IDictionary serverExtensions)
        {
            /*
             * TlsProtocol implementation validates that any server extensions received correspond to
             * client extensions sent. By default, we don't send any, and this method is not called.
             */
            if (serverExtensions != null)
            {
                /*
                 * RFC 5246 7.4.1.4.1. Servers MUST NOT send this extension.
                 */
                CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.signature_algorithms);

                CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.elliptic_curves);

                if (TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
                {
                    this.mServerECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(serverExtensions);
                }
                else
                {
                    CheckForUnexpectedServerExtension(serverExtensions, ExtensionType.ec_point_formats);
                }
            }
        }
 public override void GenerateClientKeyExchange(Stream output)
 {
     if (mAgreementCredentials == null)
     {
         this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
                                                                                      mServerECPointFormats, mECAgreePublicKey.Parameters, output);
     }
 }
        public override byte[] GeneratePremasterSecret()
        {
            if (mAgreementCredentials != null)
            {
                return(mAgreementCredentials.GenerateAgreement(mECAgreePublicKey));
            }

            if (mECAgreePrivateKey != null)
            {
                return(TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey));
            }

            throw new TlsFatalAlert(AlertDescription.internal_error);
        }
        public override void ProcessClientKeyExchange(Stream input)
        {
            if (mECAgreePublicKey != null)
            {
                // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
                return;
            }

            byte[] point = TlsUtilities.ReadOpaque8(input);

            ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;

            this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
                                                                             mServerECPointFormats, curve_params, point));
        }
        protected virtual bool AllowUnexpectedServerExtension(int extensionType, byte[] extensionData)
        {
            switch (extensionType)
            {
            case ExtensionType.elliptic_curves:
                /*
                 * Exception added based on field reports that some servers do send this, although the
                 * Supported Elliptic Curves Extension is clearly intended to be client-only. If
                 * present, we still require that it is a valid EllipticCurveList.
                 */
                TlsEccUtilities.ReadSupportedEllipticCurvesExtension(extensionData);
                return(true);

            default:
                return(false);
            }
        }
        public virtual IDictionary GetClientExtensions()
        {
            IDictionary clientExtensions = null;

            ProtocolVersion clientVersion = mContext.ClientVersion;

            /*
             * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior to 1.2.
             * Clients MUST NOT offer it if they are offering prior versions.
             */
            if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion))
            {
                // TODO Provide a way for the user to specify the acceptable hash/signature algorithms.

                this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();

                clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);

                TlsUtilities.AddSignatureAlgorithmsExtension(clientExtensions, mSupportedSignatureAlgorithms);
            }

            if (TlsEccUtilities.ContainsEccCipherSuites(GetCipherSuites()))
            {
                /*
                 * RFC 4492 5.1. A client that proposes ECC cipher suites in its ClientHello message
                 * appends these extensions (along with any others), enumerating the curves it supports
                 * and the point formats it can parse. Clients SHOULD send both the Supported Elliptic
                 * Curves Extension and the Supported Point Formats Extension.
                 */
                /*
                 * TODO Could just add all the curves since we support them all, but users may not want
                 * to use unnecessarily large fields. Need configuration options.
                 */
                this.mNamedCurves          = new int[] { NamedCurve.secp256r1, NamedCurve.secp384r1 };
                this.mClientECPointFormats = new byte[] { ECPointFormat.uncompressed,
                                                          ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };

                clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(clientExtensions);

                TlsEccUtilities.AddSupportedEllipticCurvesExtension(clientExtensions, mNamedCurves);
                TlsEccUtilities.AddSupportedPointFormatsExtension(clientExtensions, mClientECPointFormats);
            }

            return(clientExtensions);
        }
        public override void ProcessServerCertificate(Certificate serverCertificate)
        {
            if (serverCertificate.IsEmpty)
            {
                throw new TlsFatalAlert(AlertDescription.bad_certificate);
            }

            X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);

            SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;

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

            if (mTlsSigner == null)
            {
                try
                {
                    this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey((ECPublicKeyParameters)this.mServerPublicKey);
                }
                catch (InvalidCastException e)
                {
                    throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
                }

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

                TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
            }

            base.ProcessServerCertificate(serverCertificate);
        }
        public virtual void ProcessClientExtensions(IDictionary clientExtensions)
        {
            this.mClientExtensions = clientExtensions;

            if (clientExtensions != null)
            {
                this.mEncryptThenMacOffered = TlsExtensionsUtilities.HasEncryptThenMacExtension(clientExtensions);

                this.mMaxFragmentLengthOffered = TlsExtensionsUtilities.GetMaxFragmentLengthExtension(clientExtensions);
                if (mMaxFragmentLengthOffered >= 0 && !MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
                {
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }

                this.mTruncatedHMacOffered = TlsExtensionsUtilities.HasTruncatedHMacExtension(clientExtensions);

                this.mSupportedSignatureAlgorithms = TlsUtilities.GetSignatureAlgorithmsExtension(clientExtensions);
                if (this.mSupportedSignatureAlgorithms != null)
                {
                    /*
                     * RFC 5246 7.4.1.4.1. Note: this extension is not meaningful for TLS versions prior
                     * to 1.2. Clients MUST NOT offer it if they are offering prior versions.
                     */
                    if (!TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mClientVersion))
                    {
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                    }
                }

                this.mNamedCurves          = TlsEccUtilities.GetSupportedEllipticCurvesExtension(clientExtensions);
                this.mClientECPointFormats = TlsEccUtilities.GetSupportedPointFormatsExtension(clientExtensions);
            }

            /*
             * RFC 4429 4. The client MUST NOT include these extensions in the ClientHello message if it
             * does not propose any ECC cipher suites.
             *
             * NOTE: This was overly strict as there may be ECC cipher suites that we don't recognize.
             * Also, draft-ietf-tls-negotiated-ff-dhe will be overloading the 'elliptic_curves'
             * extension to explicitly allow FFDHE (i.e. non-ECC) groups.
             */
            //if (!this.mEccCipherSuitesOffered && (this.mNamedCurves != null || this.mClientECPointFormats != null))
            //    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
        }
        // IDictionary is (Int32 -> byte[])
        public virtual IDictionary GetServerExtensions()
        {
            if (this.mEncryptThenMacOffered && AllowEncryptThenMac)
            {
                /*
                 * 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.
                 */
                if (TlsUtilities.IsBlockCipherSuite(this.mSelectedCipherSuite))
                {
                    TlsExtensionsUtilities.AddEncryptThenMacExtension(CheckServerExtensions());
                }
            }

            if (this.mMaxFragmentLengthOffered >= 0 &&
                TlsUtilities.IsValidUint8(mMaxFragmentLengthOffered) &&
                MaxFragmentLength.IsValid((byte)mMaxFragmentLengthOffered))
            {
                TlsExtensionsUtilities.AddMaxFragmentLengthExtension(CheckServerExtensions(), (byte)mMaxFragmentLengthOffered);
            }

            if (this.mTruncatedHMacOffered && AllowTruncatedHMac)
            {
                TlsExtensionsUtilities.AddTruncatedHMacExtension(CheckServerExtensions());
            }

            if (this.mClientECPointFormats != null && TlsEccUtilities.IsEccCipherSuite(this.mSelectedCipherSuite))
            {
                /*
                 * RFC 4492 5.2. A server that selects an ECC cipher suite in response to a ClientHello
                 * message including a Supported Point Formats Extension appends this extension (along
                 * with others) to its ServerHello message, enumerating the point formats it can parse.
                 */
                this.mServerECPointFormats = new byte[] { ECPointFormat.uncompressed,
                                                          ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, };

                TlsEccUtilities.AddSupportedPointFormatsExtension(CheckServerExtensions(), mServerECPointFormats);
            }

            return(mServerExtensions);
        }
Example #14
0
        public override void GenerateClientKeyExchange(Stream output)
        {
            if (mPskIdentityHint == null)
            {
                mPskIdentity.SkipIdentityHint();
            }
            else
            {
                mPskIdentity.NotifyIdentityHint(mPskIdentityHint);
            }

            byte[] psk_identity = mPskIdentity.GetPskIdentity();
            if (psk_identity == null)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            this.mPsk = mPskIdentity.GetPsk();
            if (mPsk == null)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            TlsUtilities.WriteOpaque16(psk_identity, output);

            mContext.SecurityParameters.pskIdentity = psk_identity;

            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
            {
                this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
                                                                                            mDHParameters, output);
            }
            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
            {
                this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
                                                                                             mServerECPointFormats, mECAgreePublicKey.Parameters, output);
            }
            else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
            {
                this.mPremasterSecret = TlsRsaUtilities.GenerateEncryptedPreMasterSecret(mContext,
                                                                                         this.mRsaServerPublicKey, output);
            }
        }
Example #15
0
        public override void ProcessClientKeyExchange(Stream input)
        {
            byte[] psk_identity = TlsUtilities.ReadOpaque16(input);

            this.mPsk = mPskIdentityManager.GetPsk(psk_identity);
            if (mPsk == null)
            {
                throw new TlsFatalAlert(AlertDescription.unknown_psk_identity);
            }

            mContext.SecurityParameters.pskIdentity = psk_identity;

            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
            {
                BigInteger Yc = TlsDHUtilities.ReadDHParameter(input);

                this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(new DHPublicKeyParameters(Yc, mDHParameters));
            }
            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
            {
                byte[] point = TlsUtilities.ReadOpaque8(input);

                ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;

                this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
                                                                                 mServerECPointFormats, curve_params, point));
            }
            else if (this.mKeyExchange == KeyExchangeAlgorithm.RSA_PSK)
            {
                byte[] encryptedPreMasterSecret;
                if (TlsUtilities.IsSsl(mContext))
                {
                    // TODO Do any SSLv3 clients actually include the length?
                    encryptedPreMasterSecret = Streams.ReadAll(input);
                }
                else
                {
                    encryptedPreMasterSecret = TlsUtilities.ReadOpaque16(input);
                }

                this.mPremasterSecret = mServerCredentials.DecryptPreMasterSecret(encryptedPreMasterSecret);
            }
        }
Example #16
0
        public override void ProcessServerKeyExchange(Stream input)
        {
            this.mPskIdentityHint = TlsUtilities.ReadOpaque16(input);

            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
            {
                ServerDHParams serverDHParams = ServerDHParams.Parse(input);

                this.mDHAgreePublicKey = TlsDHUtilities.ValidateDHPublicKey(serverDHParams.PublicKey);
                this.mDHParameters     = mDHAgreePublicKey.Parameters;
            }
            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
            {
                ECDomainParameters ecParams = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);

                byte[] point = TlsUtilities.ReadOpaque8(input);

                this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
                                                                                 mClientECPointFormats, ecParams, point));
            }
        }
Example #17
0
        public override byte[] GenerateServerKeyExchange()
        {
            this.mPskIdentityHint = mPskIdentityManager.GetHint();

            if (this.mPskIdentityHint == null && !RequiresServerKeyExchange)
            {
                return(null);
            }

            MemoryStream buf = new MemoryStream();

            if (this.mPskIdentityHint == null)
            {
                TlsUtilities.WriteOpaque16(TlsUtilities.EmptyBytes, buf);
            }
            else
            {
                TlsUtilities.WriteOpaque16(this.mPskIdentityHint, buf);
            }

            if (this.mKeyExchange == KeyExchangeAlgorithm.DHE_PSK)
            {
                if (this.mDHParameters == null)
                {
                    throw new TlsFatalAlert(AlertDescription.internal_error);
                }

                this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
                                                                                            this.mDHParameters, buf);
            }
            else if (this.mKeyExchange == KeyExchangeAlgorithm.ECDHE_PSK)
            {
                this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
                                                                                             mNamedCurves, mClientECPointFormats, buf);
            }

            return(buf.ToArray());
        }
        public override void ProcessServerKeyExchange(Stream input)
        {
            SecurityParameters securityParameters = mContext.SecurityParameters;

            SignerInputBuffer buf   = new SignerInputBuffer();
            Stream            teeIn = new TeeInputStream(input, buf);

            ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, teeIn);

            byte[] point = TlsUtilities.ReadOpaque8(teeIn);

            DigitallySigned signed_params = ParseSignature(input);

            ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters);

            buf.UpdateSigner(signer);
            if (!signer.VerifySignature(signed_params.Signature))
            {
                throw new TlsFatalAlert(AlertDescription.decrypt_error);
            }

            this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
                                                                             mClientECPointFormats, curve_params, point));
        }
 public virtual void NotifyOfferedCipherSuites(int[] offeredCipherSuites)
 {
     this.mOfferedCipherSuites    = offeredCipherSuites;
     this.mEccCipherSuitesOffered = TlsEccUtilities.ContainsEccCipherSuites(this.mOfferedCipherSuites);
 }