summary refs log tree commit diff
path: root/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
blob: a671ebfbef27c56243147b48f0503306ce262831 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using System;
using System.Collections;
using System.IO;

using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math.EC;

namespace Org.BouncyCastle.Crypto.Tls
{
    /**
    * ECDHE key exchange (see RFC 4492)
    */
    internal class TlsECDheKeyExchange : TlsECDHKeyExchange
    {
        internal TlsECDheKeyExchange(TlsClientContext context, int keyExchange)
            : base(context, keyExchange)
        {
        }

        public override void SkipServerKeyExchange()
        {
            throw new TlsFatalAlert(AlertDescription.unexpected_message);
        }

        public override void ProcessServerKeyExchange(Stream input)
        {
            SecurityParameters securityParameters = context.SecurityParameters;

            ISigner signer = InitSigner(tlsSigner, securityParameters);
            Stream sigIn = new SignerStream(input, signer, null);

            byte curveType = TlsUtilities.ReadUint8(sigIn);
            ECDomainParameters curve_params;

            //  Currently, we only support named curves
            if (curveType == ECCurveType.named_curve)
            {
                int namedCurve = TlsUtilities.ReadUint16(sigIn);

                // TODO Check namedCurve is one we offered?

                curve_params = NamedCurveHelper.GetECParameters(namedCurve);
            }
            else
            {
                // TODO Add support for explicit curve parameters (read from sigIn)

                throw new TlsFatalAlert(AlertDescription.handshake_failure);
            }

            byte[] publicBytes = TlsUtilities.ReadOpaque8(sigIn);

            byte[] sigByte = TlsUtilities.ReadOpaque16(input);
            if (!signer.VerifySignature(sigByte))
            {
                throw new TlsFatalAlert(AlertDescription.decrypt_error);
            }

            // TODO Check curve_params not null

            ECPoint Q = curve_params.Curve.DecodePoint(publicBytes);

            this.ecAgreeServerPublicKey = ValidateECPublicKey(new ECPublicKeyParameters(Q, curve_params));
        }
        
        public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
        {
            /*
             * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable
             * with ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is
             * prohibited because the use of a long-term ECDH client key would jeopardize the
             * forward secrecy property of these algorithms.
             */
            byte[] types = certificateRequest.CertificateTypes;
            foreach (byte type in types)
            {
                switch (type)
                {
                    case ClientCertificateType.rsa_sign:
                    case ClientCertificateType.dss_sign:
                    case ClientCertificateType.ecdsa_sign:
                        break;
                    default:
                        throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                }
            }
        }
        
        public override void ProcessClientCredentials(TlsCredentials clientCredentials)
        {
            if (clientCredentials is TlsSignerCredentials)
            {
                // OK
            }
            else
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }
        }

        protected virtual ISigner InitSigner(TlsSigner tlsSigner, SecurityParameters securityParameters)
        {
            ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
            signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length);
            signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length);
            return signer;
        }
    }
}