using System; using System.Collections; using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Tls { /// Parsing and encoding of a CertificateRequest struct from RFC 4346. /// ///
    /// struct {
    ///   ClientCertificateType certificate_types<1..2^8-1>;
    ///   DistinguishedName certificate_authorities<3..2^16-1>;
    /// } CertificateRequest;
    /// 
/// Updated for RFC 5246: ///
    /// struct {
    ///   ClientCertificateType certificate_types <1..2 ^ 8 - 1>;
    ///   SignatureAndHashAlgorithm supported_signature_algorithms <2 ^ 16 - 1>;
    ///   DistinguishedName certificate_authorities <0..2 ^ 16 - 1>;
    /// } CertificateRequest;
    /// 
/// Revised for RFC 8446: ///
    /// struct {
    ///   opaque certificate_request_context <0..2 ^ 8 - 1>;
    ///   Extension extensions <2..2 ^ 16 - 1>;
    /// } CertificateRequest;
    /// 
///
/// /// public sealed class CertificateRequest { /// private static IList CheckSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, short alertDescription) { if (null == supportedSignatureAlgorithms) throw new TlsFatalAlert(alertDescription, "'signature_algorithms' is required"); return supportedSignatureAlgorithms; } private readonly byte[] m_certificateRequestContext; private readonly short[] m_certificateTypes; private readonly IList m_supportedSignatureAlgorithms; private readonly IList m_supportedSignatureAlgorithmsCert; private readonly IList m_certificateAuthorities; /// see for valid constants. /// /// an of . public CertificateRequest(short[] certificateTypes, IList supportedSignatureAlgorithms, IList certificateAuthorities) : this(null, certificateTypes, supportedSignatureAlgorithms, null, certificateAuthorities) { } // TODO[tls13] Prefer to manage the certificateRequestContext internally only? /// public CertificateRequest(byte[] certificateRequestContext, IList supportedSignatureAlgorithms, IList supportedSignatureAlgorithmsCert, IList certificateAuthorities) : this(certificateRequestContext, null, CheckSupportedSignatureAlgorithms(supportedSignatureAlgorithms, AlertDescription.internal_error), supportedSignatureAlgorithmsCert, certificateAuthorities) { /* * TODO[tls13] Removed certificateTypes, added certificate_request_context, added extensions * (required: signature_algorithms, optional: status_request, signed_certificate_timestamp, * certificate_authorities, oid_filters, signature_algorithms_cert) */ } private CertificateRequest(byte[] certificateRequestContext, short[] certificateTypes, IList supportedSignatureAlgorithms, IList supportedSignatureAlgorithmsCert, IList certificateAuthorities) { if (null != certificateRequestContext && !TlsUtilities.IsValidUint8(certificateRequestContext.Length)) throw new ArgumentException("cannot be longer than 255", "certificateRequestContext"); if (null != certificateTypes && (certificateTypes.Length < 1 || !TlsUtilities.IsValidUint8(certificateTypes.Length))) { throw new ArgumentException("should have length from 1 to 255", "certificateTypes"); } this.m_certificateRequestContext = TlsUtilities.Clone(certificateRequestContext); this.m_certificateTypes = certificateTypes; this.m_supportedSignatureAlgorithms = supportedSignatureAlgorithms; this.m_supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert; this.m_certificateAuthorities = certificateAuthorities; } public byte[] GetCertificateRequestContext() { return TlsUtilities.Clone(m_certificateRequestContext); } /// an array of certificate types /// public short[] CertificateTypes { get { return m_certificateTypes; } } /// an of (or null before TLS 1.2). /// public IList SupportedSignatureAlgorithms { get { return m_supportedSignatureAlgorithms; } } /// an optional of . May be non-null from /// TLS 1.3 onwards. public IList SupportedSignatureAlgorithmsCert { get { return m_supportedSignatureAlgorithmsCert; } } /// an of . public IList CertificateAuthorities { get { return m_certificateAuthorities; } } public bool HasCertificateRequestContext(byte[] certificateRequestContext) { return Arrays.AreEqual(m_certificateRequestContext, certificateRequestContext); } /// Encode this to a . /// the of the current connection. /// the to encode to. /// public void Encode(TlsContext context, Stream output) { ProtocolVersion negotiatedVersion = context.ServerVersion; bool isTlsV12 = TlsUtilities.IsTlsV12(negotiatedVersion); bool isTlsV13 = TlsUtilities.IsTlsV13(negotiatedVersion); if (isTlsV13 != (null != m_certificateRequestContext) || isTlsV13 != (null == m_certificateTypes) || isTlsV12 != (null != m_supportedSignatureAlgorithms) || (!isTlsV13 && (null != m_supportedSignatureAlgorithmsCert))) { throw new InvalidOperationException(); } if (isTlsV13) { TlsUtilities.WriteOpaque8(m_certificateRequestContext, output); IDictionary extensions = Platform.CreateHashtable(); TlsExtensionsUtilities.AddSignatureAlgorithmsExtension(extensions, m_supportedSignatureAlgorithms); if (null != m_supportedSignatureAlgorithmsCert) { TlsExtensionsUtilities.AddSignatureAlgorithmsCertExtension(extensions, m_supportedSignatureAlgorithmsCert); } if (null != m_certificateAuthorities) { TlsExtensionsUtilities.AddCertificateAuthoritiesExtension(extensions, m_certificateAuthorities); } byte[] extEncoding = TlsProtocol.WriteExtensionsData(extensions); TlsUtilities.WriteOpaque16(extEncoding, output); return; } TlsUtilities.WriteUint8ArrayWithUint8Length(m_certificateTypes, output); if (isTlsV12) { // TODO Check whether SignatureAlgorithm.anonymous is allowed here TlsUtilities.EncodeSupportedSignatureAlgorithms(m_supportedSignatureAlgorithms, output); } if (m_certificateAuthorities == null || m_certificateAuthorities.Count < 1) { TlsUtilities.WriteUint16(0, output); } else { IList derEncodings = Platform.CreateArrayList(m_certificateAuthorities.Count); int totalLength = 0; foreach (X509Name certificateAuthority in m_certificateAuthorities) { byte[] derEncoding = certificateAuthority.GetEncoded(Asn1Encodable.Der); derEncodings.Add(derEncoding); totalLength += derEncoding.Length + 2; } TlsUtilities.CheckUint16(totalLength); TlsUtilities.WriteUint16(totalLength, output); foreach (byte[] derEncoding in derEncodings) { TlsUtilities.WriteOpaque16(derEncoding, output); } } } /// Parse a from a /// the of the current connection. /// the to parse from. /// a object. /// public static CertificateRequest Parse(TlsContext context, Stream input) { ProtocolVersion negotiatedVersion = context.ServerVersion; bool isTlsV13 = TlsUtilities.IsTlsV13(negotiatedVersion); if (isTlsV13) { byte[] certificateRequestContext = TlsUtilities.ReadOpaque8(input); /* * TODO[tls13] required: signature_algorithms; optional: status_request, * signed_certificate_timestamp, certificate_authorities, oid_filters, * signature_algorithms_cert */ byte[] extEncoding = TlsUtilities.ReadOpaque16(input); IDictionary extensions = TlsProtocol.ReadExtensionsData13(HandshakeType.certificate_request, extEncoding); IList supportedSignatureAlgorithms13 = CheckSupportedSignatureAlgorithms( TlsExtensionsUtilities.GetSignatureAlgorithmsExtension(extensions), AlertDescription.missing_extension); IList supportedSignatureAlgorithmsCert13 = TlsExtensionsUtilities .GetSignatureAlgorithmsCertExtension(extensions); IList certificateAuthorities13 = TlsExtensionsUtilities.GetCertificateAuthoritiesExtension(extensions); return new CertificateRequest(certificateRequestContext, supportedSignatureAlgorithms13, supportedSignatureAlgorithmsCert13, certificateAuthorities13); } bool isTLSv12 = TlsUtilities.IsTlsV12(negotiatedVersion); short[] certificateTypes = TlsUtilities.ReadUint8ArrayWithUint8Length(input, 1); IList supportedSignatureAlgorithms = null; if (isTLSv12) { supportedSignatureAlgorithms = TlsUtilities.ParseSupportedSignatureAlgorithms(input); } IList certificateAuthorities = null; { byte[] certAuthData = TlsUtilities.ReadOpaque16(input); if (certAuthData.Length > 0) { certificateAuthorities = Platform.CreateArrayList(); MemoryStream bis = new MemoryStream(certAuthData, false); do { byte[] derEncoding = TlsUtilities.ReadOpaque16(bis, 1); Asn1Object asn1 = TlsUtilities.ReadDerObject(derEncoding); certificateAuthorities.Add(X509Name.GetInstance(asn1)); } while (bis.Position < bis.Length); } } return new CertificateRequest(certificateTypes, supportedSignatureAlgorithms, certificateAuthorities); } } }