Search code examples
c#connectionbouncycastletls1.2client-certificates

How to create a TLS connection with BouncyCastle in C#?


I'm trying to create a TLS connection with client authentication using BouncyCastle in C#. However I'm unsure how to properly set the context and I'm receiving an exception "Cannot be null for TLS 1.2 "signatureAndHashAlgorithm" ". My understanding is that this comes from the DefaultTlsCipherFactory used in the TlsClient not being set right. Do I also need to extend it like I have the other Tls classes or is there something else I'm missing?

var client = new TcpClient(ip.Address.ToString(), port);
var sr = new SecureRandom();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
var tlsClient = new MyTlsClient(CertChainStructure, PrivateKey);
protocol.Connect(tlsClient);

Below are the MyTlsClient and MyTlsAuthentication classes.

class MyTlsClient : DefaultTlsClient
{
    private X509CertificateStructure[] CertChain;

    private AsymmetricKeyParameter PrivateKey;

    public MyTlsClient(X509CertificateStructure[] certChain, AsymmetricKeyParameter privateKey)
    {
        CertChain = certChain;
        PrivateKey = privateKey;
    }

    public override TlsAuthentication GetAuthentication()
    {
        return new MyTlsAuthentication(CertChain, PrivateKey, this.mContext);
    }
}

class MyTlsAuthentication : TlsAuthentication
{
    private Certificate CertChain;
    private AsymmetricKeyParameter PrivateKey;
    private TlsContext Context;

    public MyTlsAuthentication(X509CertificateStructure[] certChain, AsymmetricKeyParameter privateKey, TlsContext context)
    {
        CertChain = new Certificate(certChain);
        Context = context;
        PrivateKey = privateKey;
    }

    public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
    {
        var creds = new DefaultTlsSignerCredentials(Context, CertChain, PrivateKey);
        return creds;
    }

    public void NotifyServerCertificate(Certificate serverCertificate) { }
}

UPDATE

Turns out the issue was that i wasn't supplying a signature and hash algorithm with the credentials. Adding this solved the issue and I'm able to connect with client authentication.

public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
        {
            byte[] certificateTypes = certificateRequest.CertificateTypes;
            if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign))
                return null;

            SignatureAndHashAlgorithm signatureAndHashAlgorithm = null;
            if (certificateRequest.SupportedSignatureAlgorithms != null)
            {
                foreach (SignatureAndHashAlgorithm alg in certificateRequest.SupportedSignatureAlgorithms)
                {
                    if (alg.Signature == SignatureAlgorithm.rsa)
                    {
                        signatureAndHashAlgorithm = alg;
                        break;
                    }
                }

                if (signatureAndHashAlgorithm == null)
                    return null;
            }

            var creds = new DefaultTlsSignerCredentials(mContext, CertChain, PrivateKey, signatureAndHashAlgorithm);
            return creds;
        }

Solution

  • Solved in UPDATE on question, just need to add the SignatureAndHashAlgorithm to my signer creds.