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

1

6

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;
        }
Foltz answered 9/7, 2021 at 12:56 Comment(2)
I know it's offtopic. but why do you want to use BC? HttpClient has good mutual TLS supportShippee
Wanting to verify and check a variety of things throughout the handshake even on failed connections and BouncyCastle apis seemed like I could intercept individual parts of the handshake easier.Foltz
F
0

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

Foltz answered 21/7, 2021 at 12:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.