From ed081e3fe9634391ac496bd79193a7d00dfa6f07 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 24 Sep 2022 18:09:39 +0700 Subject: (D)TLS: RFC 7250 Raw Public Keys --- crypto/src/tls/AbstractTlsClient.cs | 37 ++ crypto/src/tls/AbstractTlsServer.cs | 70 +++ crypto/src/tls/Certificate.cs | 74 +-- crypto/src/tls/DtlsClientProtocol.cs | 6 +- crypto/src/tls/DtlsServerProtocol.cs | 6 +- crypto/src/tls/SecurityParameters.cs | 9 +- crypto/src/tls/TlsClientProtocol.cs | 17 +- crypto/src/tls/TlsExtensionsUtilities.cs | 10 +- crypto/src/tls/TlsServerProtocol.cs | 12 +- crypto/src/tls/TlsUtilities.cs | 16 +- crypto/src/tls/crypto/TlsCrypto.cs | 7 + crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs | 7 +- crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs | 485 +------------------- crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs | 12 +- .../tls/crypto/impl/bc/BcTlsRawKeyCertificate.cs | 507 +++++++++++++++++++++ 15 files changed, 745 insertions(+), 530 deletions(-) create mode 100644 crypto/src/tls/crypto/impl/bc/BcTlsRawKeyCertificate.cs (limited to 'crypto/src/tls') diff --git a/crypto/src/tls/AbstractTlsClient.cs b/crypto/src/tls/AbstractTlsClient.cs index 8bfd828f1..3061f3642 100644 --- a/crypto/src/tls/AbstractTlsClient.cs +++ b/crypto/src/tls/AbstractTlsClient.cs @@ -174,6 +174,16 @@ namespace Org.BouncyCastle.Tls return null; } + protected virtual short[] GetAllowedClientCertificateTypes() + { + return null; + } + + protected virtual short[] GetAllowedServerCertificateTypes() + { + return null; + } + public virtual void Init(TlsClientContext context) { this.m_context = context; @@ -334,6 +344,33 @@ namespace Org.BouncyCastle.Tls } } + /* + * RFC 7250 4.1: + * + * If the client has no remaining certificate types to send in + * the client hello, other than the default X.509 type, it MUST omit the + * client_certificate_type extension in the client hello. + */ + short[] clientCertTypes = GetAllowedClientCertificateTypes(); + if (clientCertTypes != null && (clientCertTypes.Length > 1 || clientCertTypes[0] != CertificateType.X509)) + { + TlsExtensionsUtilities.AddClientCertificateTypeExtensionClient(clientExtensions, clientCertTypes); + } + + /* + * RFC 7250 4.1: + * + * If the client has no remaining certificate types to send in + * the client hello, other than the default X.509 certificate type, it + * MUST omit the entire server_certificate_type extension from the + * client hello. + */ + short[] serverCertTypes = GetAllowedServerCertificateTypes(); + if (serverCertTypes != null && (serverCertTypes.Length > 1 || serverCertTypes[0] != CertificateType.X509)) + { + TlsExtensionsUtilities.AddServerCertificateTypeExtensionClient(clientExtensions, serverCertTypes); + } + return clientExtensions; } diff --git a/crypto/src/tls/AbstractTlsServer.cs b/crypto/src/tls/AbstractTlsServer.cs index a41bc4710..3c62793b6 100644 --- a/crypto/src/tls/AbstractTlsServer.cs +++ b/crypto/src/tls/AbstractTlsServer.cs @@ -207,6 +207,16 @@ namespace Org.BouncyCastle.Tls return true; } + protected virtual bool PreferLocalClientCertificateTypes() + { + return false; + } + + protected virtual short[] GetAllowedClientCertificateTypes() + { + return null; + } + public virtual void Init(TlsServerContext context) { this.m_context = context; @@ -491,6 +501,66 @@ namespace Org.BouncyCastle.Tls TlsExtensionsUtilities.AddMaxFragmentLengthExtension(m_serverExtensions, m_maxFragmentLengthOffered); } + // RFC 7250 4.2 for server_certificate_type + short[] serverCertTypes = TlsExtensionsUtilities.GetServerCertificateTypeExtensionClient( + m_clientExtensions); + if (serverCertTypes != null) + { + TlsCredentials credentials = GetCredentials(); + + if (credentials == null || !Arrays.Contains(serverCertTypes, credentials.Certificate.CertificateType)) + { + // outcome 2: we support the extension but have no common types + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + // outcome 3: we support the extension and have a common type + TlsExtensionsUtilities.AddServerCertificateTypeExtensionServer(m_serverExtensions, + credentials.Certificate.CertificateType); + } + + // RFC 7250 4.2 for client_certificate_type + short[] remoteClientCertTypes = TlsExtensionsUtilities.GetClientCertificateTypeExtensionClient( + m_clientExtensions); + if (remoteClientCertTypes != null) + { + short[] localClientCertTypes = GetAllowedClientCertificateTypes(); + if (localClientCertTypes != null) + { + short[] preferredTypes; + short[] nonPreferredTypes; + if (PreferLocalClientCertificateTypes()) + { + preferredTypes = localClientCertTypes; + nonPreferredTypes = remoteClientCertTypes; + } + else + { + preferredTypes = remoteClientCertTypes; + nonPreferredTypes = localClientCertTypes; + } + + short selectedType = -1; + for (int i = 0; i < preferredTypes.Length; i++) + { + if (Arrays.Contains(nonPreferredTypes, preferredTypes[i])) + { + selectedType = preferredTypes[i]; + break; + } + } + + if (selectedType == -1) + { + // outcome 2: we support the extension but have no common types + throw new TlsFatalAlert(AlertDescription.unsupported_certificate); + } + + // outcome 3: we support the extension and have a common type + TlsExtensionsUtilities.AddClientCertificateTypeExtensionServer(m_serverExtensions, selectedType); + } // else outcome 1: we don't support the extension + } + return m_serverExtensions; } diff --git a/crypto/src/tls/Certificate.cs b/crypto/src/tls/Certificate.cs index c7f08b2aa..30b14368b 100644 --- a/crypto/src/tls/Certificate.cs +++ b/crypto/src/tls/Certificate.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.IO; - +using Org.BouncyCastle.Pqc.Crypto.Lms; using Org.BouncyCastle.Tls.Crypto; namespace Org.BouncyCastle.Tls @@ -25,18 +25,8 @@ namespace Org.BouncyCastle.Tls public sealed class ParseOptions { - private int m_maxChainLength = int.MaxValue; - - public int MaxChainLength - { - get { return m_maxChainLength; } - } - - public ParseOptions SetMaxChainLength(int maxChainLength) - { - this.m_maxChainLength = maxChainLength; - return this; - } + public short CertificateType { get; set; } = Tls.CertificateType.X509; + public int MaxChainLength { get; set; } = int.MaxValue; } private static CertificateEntry[] Convert(TlsCertificate[] certificateList) @@ -55,22 +45,29 @@ namespace Org.BouncyCastle.Tls private readonly byte[] m_certificateRequestContext; private readonly CertificateEntry[] m_certificateEntryList; + private readonly short m_certificateType; public Certificate(TlsCertificate[] certificateList) : this(null, Convert(certificateList)) { } - // TODO[tls13] Prefer to manage the certificateRequestContext internally only? public Certificate(byte[] certificateRequestContext, CertificateEntry[] certificateEntryList) + : this(Tls.CertificateType.X509, certificateRequestContext, certificateEntryList) + { + } + + // TODO[tls13] Prefer to manage the certificateRequestContext internally only? + public Certificate(short certificateType, byte[] certificateRequestContext, CertificateEntry[] certificateEntryList) { if (null != certificateRequestContext && !TlsUtilities.IsValidUint8(certificateRequestContext.Length)) throw new ArgumentException("cannot be longer than 255", "certificateRequestContext"); if (TlsUtilities.IsNullOrContainsNull(certificateEntryList)) throw new ArgumentException("cannot be null or contain any nulls", "certificateEntryList"); - this.m_certificateRequestContext = TlsUtilities.Clone(certificateRequestContext); - this.m_certificateEntryList = certificateEntryList; + m_certificateRequestContext = TlsUtilities.Clone(certificateRequestContext); + m_certificateEntryList = certificateEntryList; + m_certificateType = certificateType; } public byte[] GetCertificateRequestContext() @@ -99,22 +96,13 @@ namespace Org.BouncyCastle.Tls return CloneCertificateEntryList(); } - public short CertificateType - { - get { return Tls.CertificateType.X509; } - } + public short CertificateType => m_certificateType; - public int Length - { - get { return m_certificateEntryList.Length; } - } + public int Length => m_certificateEntryList.Length; /// true if this certificate chain contains no certificates, or false otherwise. /// - public bool IsEmpty - { - get { return m_certificateEntryList.Length == 0; } - } + public bool IsEmpty => m_certificateEntryList.Length == 0; /// Encode this to a , and optionally calculate the /// "end point hash" (per RFC 5929's tls-server-end-point binding). @@ -168,8 +156,13 @@ namespace Org.BouncyCastle.Tls } } - TlsUtilities.CheckUint24(totalLength); - TlsUtilities.WriteUint24((int)totalLength, messageOutput); + // RFC 7250 indicates the raw key is not wrapped in a cert list like X509 is + // but RFC 8446 wraps it in a CertificateEntry, which is inside certificate_list + if (isTlsV13 || m_certificateType != Tls.CertificateType.RawPublicKey) + { + TlsUtilities.CheckUint24(totalLength); + TlsUtilities.WriteUint24((int)totalLength, messageOutput); + } for (int i = 0; i < count; ++i) { @@ -195,6 +188,7 @@ namespace Org.BouncyCastle.Tls { SecurityParameters securityParameters = context.SecurityParameters; bool isTlsV13 = TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion); + short certType = options.CertificateType; byte[] certificateRequestContext = null; if (isTlsV13) @@ -207,7 +201,7 @@ namespace Org.BouncyCastle.Tls { return !isTlsV13 ? EmptyChain : certificateRequestContext.Length < 1 ? EmptyChainTls13 - : new Certificate(certificateRequestContext, EmptyCertEntries); + : new Certificate(certType, certificateRequestContext, EmptyCertEntries); } byte[] certListData = TlsUtilities.ReadFully(totalLength, messageInput); @@ -225,8 +219,20 @@ namespace Org.BouncyCastle.Tls "Certificate chain longer than maximum (" + maxChainLength + ")"); } - byte[] derEncoding = TlsUtilities.ReadOpaque24(buf, 1); - TlsCertificate cert = crypto.CreateCertificate(derEncoding); + // RFC 7250 indicates the raw key is not wrapped in a cert list like X509 is + // but RFC 8446 wraps it in a CertificateEntry, which is inside certificate_list + byte[] derEncoding; + if (isTlsV13 || certType != Tls.CertificateType.RawPublicKey) + { + derEncoding = TlsUtilities.ReadOpaque24(buf, 1); + } + else + { + derEncoding = certListData; + buf.Seek(totalLength, SeekOrigin.Current); + } + + TlsCertificate cert = crypto.CreateCertificate(certType, derEncoding); if (certificate_list.Count < 1 && endPointHashOutput != null) { @@ -250,7 +256,7 @@ namespace Org.BouncyCastle.Tls certificateList[i] = (CertificateEntry)certificate_list[i]; } - return new Certificate(certificateRequestContext, certificateList); + return new Certificate(certType, certificateRequestContext, certificateList); } private static void CalculateEndPointHash(TlsContext context, TlsCertificate cert, byte[] encoding, diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs index 3e3aab662..b8c09617a 100644 --- a/crypto/src/tls/DtlsClientProtocol.cs +++ b/crypto/src/tls/DtlsClientProtocol.cs @@ -579,6 +579,10 @@ namespace Org.BouncyCastle.Tls TlsProtocol.AssertEmpty(buf); state.certificateRequest = TlsUtilities.ValidateCertificateRequest(certificateRequest, state.keyExchange); + + state.clientContext.SecurityParameters.m_clientCertificateType = + TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(state.serverExtensions, + CertificateType.X509); } /// @@ -633,7 +637,7 @@ namespace Org.BouncyCastle.Tls protected virtual void ProcessServerCertificate(ClientHandshakeState state, byte[] body) { state.authentication = TlsUtilities.ReceiveServerCertificate(state.clientContext, state.client, - new MemoryStream(body, false)); + new MemoryStream(body, false), state.serverExtensions); } /// diff --git a/crypto/src/tls/DtlsServerProtocol.cs b/crypto/src/tls/DtlsServerProtocol.cs index e4ce4d6be..b42f97b64 100644 --- a/crypto/src/tls/DtlsServerProtocol.cs +++ b/crypto/src/tls/DtlsServerProtocol.cs @@ -637,7 +637,11 @@ namespace Org.BouncyCastle.Tls MemoryStream buf = new MemoryStream(body, false); Certificate.ParseOptions options = new Certificate.ParseOptions() - .SetMaxChainLength(state.server.GetMaxCertificateChainLength()); + { + CertificateType = TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer( + state.clientExtensions, CertificateType.X509), + MaxChainLength = state.server.GetMaxCertificateChainLength(), + }; Certificate clientCertificate = Certificate.Parse(options, state.serverContext, buf, null); diff --git a/crypto/src/tls/SecurityParameters.cs b/crypto/src/tls/SecurityParameters.cs index 7891549b6..7775ca7c7 100644 --- a/crypto/src/tls/SecurityParameters.cs +++ b/crypto/src/tls/SecurityParameters.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Org.BouncyCastle.Tls.Crypto; @@ -52,6 +51,7 @@ namespace Org.BouncyCastle.Tls internal Certificate m_peerCertificate = null; internal ProtocolVersion m_negotiatedVersion = null; internal int m_statusRequestVersion = 0; + internal short m_clientCertificateType = -1; // TODO[tls-ops] Investigate whether we can handle verify data using TlsSecret internal byte[] m_localVerifyData = null; @@ -100,6 +100,11 @@ namespace Org.BouncyCastle.Tls get { return m_cipherSuite; } } + public short ClientCertificateType + { + get { return m_clientCertificateType; } + } + public short[] ClientCertTypes { get { return m_clientCertTypes; } diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs index fc3894710..b7295bcc5 100644 --- a/crypto/src/tls/TlsClientProtocol.cs +++ b/crypto/src/tls/TlsClientProtocol.cs @@ -380,8 +380,8 @@ namespace Org.BouncyCastle.Tls * NOTE: Certificate processing (including authentication) is delayed to allow for a * possible CertificateStatus message. */ - this.m_authentication = TlsUtilities.ReceiveServerCertificate(m_tlsClientContext, m_tlsClient, - buf); + m_authentication = TlsUtilities.ReceiveServerCertificate(m_tlsClientContext, m_tlsClient, buf, + m_serverExtensions); break; } default: @@ -1364,6 +1364,10 @@ namespace Org.BouncyCastle.Tls this.m_certificateRequest = certificateRequest; + m_tlsClientContext.SecurityParameters.m_clientCertificateType = + TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(m_serverExtensions, + CertificateType.X509); + TlsUtilities.EstablishServerSigAlgs(m_tlsClientContext.SecurityParameters, certificateRequest); } @@ -1467,7 +1471,8 @@ namespace Org.BouncyCastle.Tls if (m_selectedPsk13) throw new TlsFatalAlert(AlertDescription.unexpected_message); - this.m_authentication = TlsUtilities.Receive13ServerCertificate(m_tlsClientContext, m_tlsClient, buf); + m_authentication = TlsUtilities.Receive13ServerCertificate(m_tlsClientContext, m_tlsClient, buf, + m_serverExtensions); // NOTE: In TLS 1.3 we don't have to wait for a possible CertificateStatus message. HandleServerCertificate(); @@ -1509,7 +1514,11 @@ namespace Org.BouncyCastle.Tls AssertEmpty(buf); - this.m_certificateRequest = TlsUtilities.ValidateCertificateRequest(certificateRequest, m_keyExchange); + m_certificateRequest = TlsUtilities.ValidateCertificateRequest(certificateRequest, m_keyExchange); + + m_tlsClientContext.SecurityParameters.m_clientCertificateType = + TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(m_serverExtensions, + CertificateType.X509); } /// diff --git a/crypto/src/tls/TlsExtensionsUtilities.cs b/crypto/src/tls/TlsExtensionsUtilities.cs index 5a97e1efc..46d42417c 100644 --- a/crypto/src/tls/TlsExtensionsUtilities.cs +++ b/crypto/src/tls/TlsExtensionsUtilities.cs @@ -302,10 +302,11 @@ namespace Org.BouncyCastle.Tls } /// - public static short GetClientCertificateTypeExtensionServer(IDictionary extensions) + public static short GetClientCertificateTypeExtensionServer(IDictionary extensions, + short defaultValue) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type); - return extensionData == null ? (short)-1 : ReadCertificateTypeExtensionServer(extensionData); + return extensionData == null ? defaultValue : ReadCertificateTypeExtensionServer(extensionData); } /// @@ -415,10 +416,11 @@ namespace Org.BouncyCastle.Tls } /// - public static short GetServerCertificateTypeExtensionServer(IDictionary extensions) + public static short GetServerCertificateTypeExtensionServer(IDictionary extensions, + short defaultValue) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type); - return extensionData == null ? (short)-1 : ReadCertificateTypeExtensionServer(extensionData); + return extensionData == null ? defaultValue : ReadCertificateTypeExtensionServer(extensionData); } /// diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs index 3acbe90df..bf4b9119a 100644 --- a/crypto/src/tls/TlsServerProtocol.cs +++ b/crypto/src/tls/TlsServerProtocol.cs @@ -1290,7 +1290,11 @@ namespace Org.BouncyCastle.Tls throw new TlsFatalAlert(AlertDescription.unexpected_message); Certificate.ParseOptions options = new Certificate.ParseOptions() - .SetMaxChainLength(m_tlsServer.GetMaxCertificateChainLength()); + { + CertificateType = TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(m_serverExtensions, + CertificateType.X509), + MaxChainLength = m_tlsServer.GetMaxCertificateChainLength(), + }; Certificate clientCertificate = Certificate.Parse(options, m_tlsServerContext, buf, null); @@ -1326,7 +1330,11 @@ namespace Org.BouncyCastle.Tls throw new TlsFatalAlert(AlertDescription.unexpected_message); Certificate.ParseOptions options = new Certificate.ParseOptions() - .SetMaxChainLength(m_tlsServer.GetMaxCertificateChainLength()); + { + CertificateType = TlsExtensionsUtilities.GetClientCertificateTypeExtensionServer(m_serverExtensions, + CertificateType.X509), + MaxChainLength = m_tlsServer.GetMaxCertificateChainLength(), + }; Certificate clientCertificate = Certificate.Parse(options, m_tlsServerContext, buf, null); diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs index 97895e8f2..a417336be 100644 --- a/crypto/src/tls/TlsUtilities.cs +++ b/crypto/src/tls/TlsUtilities.cs @@ -4756,7 +4756,7 @@ namespace Org.BouncyCastle.Tls } internal static TlsAuthentication ReceiveServerCertificate(TlsClientContext clientContext, TlsClient client, - MemoryStream buf) + MemoryStream buf, IDictionary serverExtensions) { SecurityParameters securityParameters = clientContext.SecurityParameters; if (KeyExchangeAlgorithm.IsAnonymous(securityParameters.KeyExchangeAlgorithm) @@ -4768,7 +4768,11 @@ namespace Org.BouncyCastle.Tls MemoryStream endPointHash = new MemoryStream(); Certificate.ParseOptions options = new Certificate.ParseOptions() - .SetMaxChainLength(client.GetMaxCertificateChainLength()); + { + CertificateType = TlsExtensionsUtilities.GetServerCertificateTypeExtensionServer(serverExtensions, + CertificateType.X509), + MaxChainLength = client.GetMaxCertificateChainLength(), + }; Certificate serverCertificate = Certificate.Parse(options, clientContext, buf, endPointHash); @@ -4788,14 +4792,18 @@ namespace Org.BouncyCastle.Tls } internal static TlsAuthentication Receive13ServerCertificate(TlsClientContext clientContext, TlsClient client, - MemoryStream buf) + MemoryStream buf, IDictionary serverExtensions) { SecurityParameters securityParameters = clientContext.SecurityParameters; if (null != securityParameters.PeerCertificate) throw new TlsFatalAlert(AlertDescription.unexpected_message); Certificate.ParseOptions options = new Certificate.ParseOptions() - .SetMaxChainLength(client.GetMaxCertificateChainLength()); + { + CertificateType = TlsExtensionsUtilities.GetServerCertificateTypeExtensionServer(serverExtensions, + CertificateType.X509), + MaxChainLength = client.GetMaxCertificateChainLength(), + }; Certificate serverCertificate = Certificate.Parse(options, clientContext, buf, null); diff --git a/crypto/src/tls/crypto/TlsCrypto.cs b/crypto/src/tls/crypto/TlsCrypto.cs index c9d00cbb0..d9c2c0da1 100644 --- a/crypto/src/tls/crypto/TlsCrypto.cs +++ b/crypto/src/tls/crypto/TlsCrypto.cs @@ -112,6 +112,13 @@ namespace Org.BouncyCastle.Tls.Crypto /// if there is an issue on decoding or constructing the certificate. TlsCertificate CreateCertificate(byte[] encoding); + /// Create a TlsCertificate from an ASN.1 binary encoding of a certificate. + /// Certificate type as per IANA TLS Certificate Types registry. + /// DER/BER encoding of the certificate of interest. + /// a TlsCertificate. + /// if there is an issue on decoding or constructing the certificate. + TlsCertificate CreateCertificate(short type, byte[] encoding); + /// Create a cipher for the specified encryption and MAC algorithms. /// /// See enumeration classes , for appropriate diff --git a/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs b/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs index b2e1e7fe0..607f12778 100644 --- a/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs +++ b/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs @@ -48,7 +48,12 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl public abstract SecureRandom SecureRandom { get; } - public abstract TlsCertificate CreateCertificate(byte[] encoding); + public virtual TlsCertificate CreateCertificate(byte[] encoding) + { + return CreateCertificate(CertificateType.X509, encoding); + } + + public abstract TlsCertificate CreateCertificate(short type, byte[] encoding); public abstract TlsCipher CreateCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, int macAlgorithm); diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs b/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs index 7e946ce23..f64d8332d 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsCertificate.cs @@ -3,19 +3,14 @@ using System.IO; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Engines; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Signers; using Org.BouncyCastle.Math; -using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Tls.Crypto.Impl.BC { /// Implementation class for a single X.509 certificate based on the BC light-weight API. public class BcTlsCertificate - : TlsCertificate + : BcTlsRawKeyCertificate { /// public static BcTlsCertificate Convert(BcTlsCrypto crypto, TlsCertificate certificate) @@ -40,15 +35,8 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC } } - protected readonly BcTlsCrypto m_crypto; protected readonly X509CertificateStructure m_certificate; - protected DHPublicKeyParameters m_pubKeyDH = null; - protected ECPublicKeyParameters m_pubKeyEC = null; - protected Ed25519PublicKeyParameters m_pubKeyEd25519 = null; - protected Ed448PublicKeyParameters m_pubKeyEd448 = null; - protected RsaKeyParameters m_pubKeyRsa = null; - /// public BcTlsCertificate(BcTlsCrypto crypto, byte[] encoding) : this(crypto, ParseCertificate(encoding)) @@ -56,204 +44,21 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC } public BcTlsCertificate(BcTlsCrypto crypto, X509CertificateStructure certificate) + : base(crypto, certificate.SubjectPublicKeyInfo) { - this.m_crypto = crypto; - this.m_certificate = certificate; + m_certificate = certificate; } - /// - public virtual TlsEncryptor CreateEncryptor(int tlsCertificateRole) - { - ValidateKeyUsage(KeyUsage.KeyEncipherment); - - switch (tlsCertificateRole) - { - case TlsCertificateRole.RsaEncryption: - { - this.m_pubKeyRsa = GetPubKeyRsa(); - return new BcTlsRsaEncryptor(m_crypto, m_pubKeyRsa); - } - // TODO[gmssl] - //case TlsCertificateRole.Sm2Encryption: - //{ - // this.m_pubKeyEC = GetPubKeyEC(); - // return new BcTlsSM2Encryptor(m_crypto, m_pubKeyEC); - //} - } - - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } + public virtual X509CertificateStructure X509CertificateStructure => m_certificate; /// - public virtual TlsVerifier CreateVerifier(short signatureAlgorithm) - { - switch (signatureAlgorithm) - { - case SignatureAlgorithm.ed25519: - case SignatureAlgorithm.ed448: - { - int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); - Tls13Verifier tls13Verifier = CreateVerifier(signatureScheme); - return new LegacyTls13Verifier(signatureScheme, tls13Verifier); - } - } - - ValidateKeyUsage(KeyUsage.DigitalSignature); - - switch (signatureAlgorithm) - { - case SignatureAlgorithm.dsa: - return new BcTlsDsaVerifier(m_crypto, GetPubKeyDss()); - - case SignatureAlgorithm.ecdsa: - return new BcTlsECDsaVerifier(m_crypto, GetPubKeyEC()); - - case SignatureAlgorithm.rsa: - { - ValidateRsa_Pkcs1(); - return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); - } - - case SignatureAlgorithm.rsa_pss_pss_sha256: - case SignatureAlgorithm.rsa_pss_pss_sha384: - case SignatureAlgorithm.rsa_pss_pss_sha512: - { - ValidateRsa_Pss_Pss(signatureAlgorithm); - int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); - return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); - } - - case SignatureAlgorithm.rsa_pss_rsae_sha256: - case SignatureAlgorithm.rsa_pss_rsae_sha384: - case SignatureAlgorithm.rsa_pss_rsae_sha512: - { - ValidateRsa_Pss_Rsae(); - int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); - return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); - } - - default: - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - } - - /// - public virtual Tls13Verifier CreateVerifier(int signatureScheme) - { - ValidateKeyUsage(KeyUsage.DigitalSignature); - - switch (signatureScheme) - { - case SignatureScheme.ecdsa_brainpoolP256r1tls13_sha256: - case SignatureScheme.ecdsa_brainpoolP384r1tls13_sha384: - case SignatureScheme.ecdsa_brainpoolP512r1tls13_sha512: - case SignatureScheme.ecdsa_secp256r1_sha256: - case SignatureScheme.ecdsa_secp384r1_sha384: - case SignatureScheme.ecdsa_secp521r1_sha512: - case SignatureScheme.ecdsa_sha1: - { - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); - - ISigner verifier = new DsaDigestSigner(new ECDsaSigner(), digest); - verifier.Init(false, GetPubKeyEC()); - - return new BcTls13Verifier(verifier); - } - - case SignatureScheme.ed25519: - { - Ed25519Signer verifier = new Ed25519Signer(); - verifier.Init(false, GetPubKeyEd25519()); - - return new BcTls13Verifier(verifier); - } - - case SignatureScheme.ed448: - { - Ed448Signer verifier = new Ed448Signer(TlsUtilities.EmptyBytes); - verifier.Init(false, GetPubKeyEd448()); - - return new BcTls13Verifier(verifier); - } - - case SignatureScheme.rsa_pkcs1_sha1: - case SignatureScheme.rsa_pkcs1_sha256: - case SignatureScheme.rsa_pkcs1_sha384: - case SignatureScheme.rsa_pkcs1_sha512: - { - ValidateRsa_Pkcs1(); - - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); - - RsaDigestSigner verifier = new RsaDigestSigner(digest, - TlsCryptoUtilities.GetOidForHash(cryptoHashAlgorithm)); - verifier.Init(false, GetPubKeyRsa()); - - return new BcTls13Verifier(verifier); - } - - case SignatureScheme.rsa_pss_pss_sha256: - case SignatureScheme.rsa_pss_pss_sha384: - case SignatureScheme.rsa_pss_pss_sha512: - { - ValidateRsa_Pss_Pss(SignatureScheme.GetSignatureAlgorithm(signatureScheme)); - - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); - - PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); - verifier.Init(false, GetPubKeyRsa()); - - return new BcTls13Verifier(verifier); - } - - case SignatureScheme.rsa_pss_rsae_sha256: - case SignatureScheme.rsa_pss_rsae_sha384: - case SignatureScheme.rsa_pss_rsae_sha512: - { - ValidateRsa_Pss_Rsae(); - - int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); - IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); - - PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); - verifier.Init(false, GetPubKeyRsa()); - - return new BcTls13Verifier(verifier); - } - - // TODO[RFC 8998] - //case SignatureScheme.sm2sig_sm3: - //{ - // ParametersWithID parametersWithID = new ParametersWithID(GetPubKeyEC(), - // Strings.ToByteArray("TLSv1.3+GM+Cipher+Suite")); - - // SM2Signer verifier = new SM2Signer(); - // verifier.Init(false, parametersWithID); - - // return new BcTls13Verifier(verifier); - //} - - default: - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - } - - public virtual X509CertificateStructure X509CertificateStructure - { - get { return m_certificate; } - } - - /// - public virtual byte[] GetEncoded() + public override byte[] GetEncoded() { return m_certificate.GetEncoded(Asn1Encodable.Der); } /// - public virtual byte[] GetExtension(DerObjectIdentifier extensionOid) + public override byte[] GetExtension(DerObjectIdentifier extensionOid) { X509Extensions extensions = m_certificate.TbsCertificate.Extensions; if (extensions != null) @@ -267,191 +72,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC return null; } - public virtual BigInteger SerialNumber - { - get { return m_certificate.SerialNumber.Value; } - } - - public virtual string SigAlgOid - { - get { return m_certificate.SignatureAlgorithm.Algorithm.Id; } - } - - public virtual Asn1Encodable GetSigAlgParams() - { - return m_certificate.SignatureAlgorithm.Parameters; - } - - /// - public virtual short GetLegacySignatureAlgorithm() - { - AsymmetricKeyParameter publicKey = GetPublicKey(); - if (publicKey.IsPrivate) - throw new TlsFatalAlert(AlertDescription.internal_error); - - if (!SupportsKeyUsage(KeyUsage.DigitalSignature)) - return -1; - - /* - * RFC 5246 7.4.6. Client Certificate - */ + public override BigInteger SerialNumber => m_certificate.SerialNumber.Value; - /* - * RSA public key; the certificate MUST allow the key to be used for signing with the - * signature scheme and hash algorithm that will be employed in the certificate verify - * message. - */ - if (publicKey is RsaKeyParameters) - return SignatureAlgorithm.rsa; + public override string SigAlgOid => m_certificate.SignatureAlgorithm.Algorithm.Id; - /* - * DSA public key; the certificate MUST allow the key to be used for signing with the - * hash algorithm that will be employed in the certificate verify message. - */ - if (publicKey is DsaPublicKeyParameters) - return SignatureAlgorithm.dsa; + public override Asn1Encodable GetSigAlgParams() => m_certificate.SignatureAlgorithm.Parameters; - /* - * ECDSA-capable public key; the certificate MUST allow the key to be used for signing - * with the hash algorithm that will be employed in the certificate verify message; the - * public key MUST use a curve and point format supported by the server. - */ - if (publicKey is ECPublicKeyParameters) - { - // TODO Check the curve and point format - return SignatureAlgorithm.ecdsa; - } - - return -1; - } - - /// - public virtual DHPublicKeyParameters GetPubKeyDH() - { - try - { - return (DHPublicKeyParameters)GetPublicKey(); - } - catch (InvalidCastException e) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); - } - } - - /// - public virtual DsaPublicKeyParameters GetPubKeyDss() - { - try - { - return (DsaPublicKeyParameters)GetPublicKey(); - } - catch (InvalidCastException e) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); - } - } - - /// - public virtual ECPublicKeyParameters GetPubKeyEC() - { - try - { - return (ECPublicKeyParameters)GetPublicKey(); - } - catch (InvalidCastException e) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); - } - } - - /// - public virtual Ed25519PublicKeyParameters GetPubKeyEd25519() - { - try - { - return (Ed25519PublicKeyParameters)GetPublicKey(); - } - catch (InvalidCastException e) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); - } - } - - /// - public virtual Ed448PublicKeyParameters GetPubKeyEd448() - { - try - { - return (Ed448PublicKeyParameters)GetPublicKey(); - } - catch (InvalidCastException e) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); - } - } - - /// - public virtual RsaKeyParameters GetPubKeyRsa() - { - try - { - return (RsaKeyParameters)GetPublicKey(); - } - catch (InvalidCastException e) - { - throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); - } - } - - /// - public virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm) - { - return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.DigitalSignature); - } - - /// - public virtual bool SupportsSignatureAlgorithmCA(short signatureAlgorithm) - { - return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.KeyCertSign); - } - - /// - public virtual TlsCertificate CheckUsageInRole(int tlsCertificateRole) - { - switch (tlsCertificateRole) - { - case TlsCertificateRole.DH: - { - ValidateKeyUsage(KeyUsage.KeyAgreement); - this.m_pubKeyDH = GetPubKeyDH(); - return this; - } - case TlsCertificateRole.ECDH: - { - ValidateKeyUsage(KeyUsage.KeyAgreement); - this.m_pubKeyEC = GetPubKeyEC(); - return this; - } - } - - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - /// - protected virtual AsymmetricKeyParameter GetPublicKey() - { - SubjectPublicKeyInfo keyInfo = m_certificate.SubjectPublicKeyInfo; - try - { - return PublicKeyFactory.CreateKey(keyInfo); - } - catch (Exception e) - { - throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); - } - } - - protected virtual bool SupportsKeyUsage(int keyUsageBits) + protected override bool SupportsKeyUsage(int keyUsageBits) { X509Extensions exts = m_certificate.TbsCertificate.Extensions; if (exts != null) @@ -466,97 +93,5 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC } return true; } - - protected virtual bool SupportsRsa_Pkcs1() - { - AlgorithmIdentifier pubKeyAlgID = m_certificate.SubjectPublicKeyInfo.AlgorithmID; - return RsaUtilities.SupportsPkcs1(pubKeyAlgID); - } - - protected virtual bool SupportsRsa_Pss_Pss(short signatureAlgorithm) - { - AlgorithmIdentifier pubKeyAlgID = m_certificate.SubjectPublicKeyInfo.AlgorithmID; - return RsaUtilities.SupportsPss_Pss(signatureAlgorithm, pubKeyAlgID); - } - - protected virtual bool SupportsRsa_Pss_Rsae() - { - AlgorithmIdentifier pubKeyAlgID = m_certificate.SubjectPublicKeyInfo.AlgorithmID; - return RsaUtilities.SupportsPss_Rsae(pubKeyAlgID); - } - - /// - protected virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm, int keyUsage) - { - if (!SupportsKeyUsage(keyUsage)) - return false; - - AsymmetricKeyParameter publicKey = GetPublicKey(); - - switch (signatureAlgorithm) - { - case SignatureAlgorithm.rsa: - return SupportsRsa_Pkcs1() - && publicKey is RsaKeyParameters; - - case SignatureAlgorithm.dsa: - return publicKey is DsaPublicKeyParameters; - - case SignatureAlgorithm.ecdsa: - case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: - case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: - case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: - return publicKey is ECPublicKeyParameters; - - case SignatureAlgorithm.ed25519: - return publicKey is Ed25519PublicKeyParameters; - - case SignatureAlgorithm.ed448: - return publicKey is Ed448PublicKeyParameters; - - case SignatureAlgorithm.rsa_pss_rsae_sha256: - case SignatureAlgorithm.rsa_pss_rsae_sha384: - case SignatureAlgorithm.rsa_pss_rsae_sha512: - return SupportsRsa_Pss_Rsae() - && publicKey is RsaKeyParameters; - - case SignatureAlgorithm.rsa_pss_pss_sha256: - case SignatureAlgorithm.rsa_pss_pss_sha384: - case SignatureAlgorithm.rsa_pss_pss_sha512: - return SupportsRsa_Pss_Pss(signatureAlgorithm) - && publicKey is RsaKeyParameters; - - default: - return false; - } - } - - /// - public virtual void ValidateKeyUsage(int keyUsageBits) - { - if (!SupportsKeyUsage(keyUsageBits)) - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - /// - protected virtual void ValidateRsa_Pkcs1() - { - if (!SupportsRsa_Pkcs1()) - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - /// - protected virtual void ValidateRsa_Pss_Pss(short signatureAlgorithm) - { - if (!SupportsRsa_Pss_Pss(signatureAlgorithm)) - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } - - /// - protected virtual void ValidateRsa_Pss_Rsae() - { - if (!SupportsRsa_Pss_Rsae()) - throw new TlsFatalAlert(AlertDescription.certificate_unknown); - } } } diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs index e84361e49..3f63f9e83 100644 --- a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs +++ b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs @@ -42,9 +42,17 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC get { return m_entropySource; } } - public override TlsCertificate CreateCertificate(byte[] encoding) + public override TlsCertificate CreateCertificate(short type, byte[] encoding) { - return new BcTlsCertificate(this, encoding); + switch (type) + { + case CertificateType.X509: + return new BcTlsCertificate(this, encoding); + case CertificateType.RawPublicKey: + return new BcTlsRawKeyCertificate(this, encoding); + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } } public override TlsCipher CreateCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm, diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsRawKeyCertificate.cs b/crypto/src/tls/crypto/impl/bc/BcTlsRawKeyCertificate.cs new file mode 100644 index 000000000..4d208b35a --- /dev/null +++ b/crypto/src/tls/crypto/impl/bc/BcTlsRawKeyCertificate.cs @@ -0,0 +1,507 @@ +using System; +using System.IO; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Cmp; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Tls.Crypto.Impl.BC +{ + /// Implementation class for a single X.509 certificate based on the BC light-weight API. + public class BcTlsRawKeyCertificate + : TlsCertificate + { + protected readonly BcTlsCrypto m_crypto; + protected readonly SubjectPublicKeyInfo m_keyInfo; + + protected DHPublicKeyParameters m_pubKeyDH = null; + protected ECPublicKeyParameters m_pubKeyEC = null; + protected Ed25519PublicKeyParameters m_pubKeyEd25519 = null; + protected Ed448PublicKeyParameters m_pubKeyEd448 = null; + protected RsaKeyParameters m_pubKeyRsa = null; + + /// + public BcTlsRawKeyCertificate(BcTlsCrypto crypto, byte[] encoding) + : this(crypto, SubjectPublicKeyInfo.GetInstance(encoding)) + { + } + + public BcTlsRawKeyCertificate(BcTlsCrypto crypto, SubjectPublicKeyInfo keyInfo) + { + m_crypto = crypto; + m_keyInfo = keyInfo; + } + + public virtual SubjectPublicKeyInfo SubjectPublicKeyInfo => m_keyInfo; + + /// + public virtual TlsEncryptor CreateEncryptor(int tlsCertificateRole) + { + ValidateKeyUsage(KeyUsage.KeyEncipherment); + + switch (tlsCertificateRole) + { + case TlsCertificateRole.RsaEncryption: + { + this.m_pubKeyRsa = GetPubKeyRsa(); + return new BcTlsRsaEncryptor(m_crypto, m_pubKeyRsa); + } + // TODO[gmssl] + //case TlsCertificateRole.Sm2Encryption: + //{ + // this.m_pubKeyEC = GetPubKeyEC(); + // return new BcTlsSM2Encryptor(m_crypto, m_pubKeyEC); + //} + } + + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + /// + public virtual TlsVerifier CreateVerifier(short signatureAlgorithm) + { + switch (signatureAlgorithm) + { + case SignatureAlgorithm.ed25519: + case SignatureAlgorithm.ed448: + { + int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); + Tls13Verifier tls13Verifier = CreateVerifier(signatureScheme); + return new LegacyTls13Verifier(signatureScheme, tls13Verifier); + } + } + + ValidateKeyUsage(KeyUsage.DigitalSignature); + + switch (signatureAlgorithm) + { + case SignatureAlgorithm.dsa: + return new BcTlsDsaVerifier(m_crypto, GetPubKeyDss()); + + case SignatureAlgorithm.ecdsa: + return new BcTlsECDsaVerifier(m_crypto, GetPubKeyEC()); + + case SignatureAlgorithm.rsa: + { + ValidateRsa_Pkcs1(); + return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); + } + + case SignatureAlgorithm.rsa_pss_pss_sha256: + case SignatureAlgorithm.rsa_pss_pss_sha384: + case SignatureAlgorithm.rsa_pss_pss_sha512: + { + ValidateRsa_Pss_Pss(signatureAlgorithm); + int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); + return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); + } + + case SignatureAlgorithm.rsa_pss_rsae_sha256: + case SignatureAlgorithm.rsa_pss_rsae_sha384: + case SignatureAlgorithm.rsa_pss_rsae_sha512: + { + ValidateRsa_Pss_Rsae(); + int signatureScheme = SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm); + return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); + } + + default: + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } + + /// + public virtual Tls13Verifier CreateVerifier(int signatureScheme) + { + ValidateKeyUsage(KeyUsage.DigitalSignature); + + switch (signatureScheme) + { + case SignatureScheme.ecdsa_brainpoolP256r1tls13_sha256: + case SignatureScheme.ecdsa_brainpoolP384r1tls13_sha384: + case SignatureScheme.ecdsa_brainpoolP512r1tls13_sha512: + case SignatureScheme.ecdsa_secp256r1_sha256: + case SignatureScheme.ecdsa_secp384r1_sha384: + case SignatureScheme.ecdsa_secp521r1_sha512: + case SignatureScheme.ecdsa_sha1: + { + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + ISigner verifier = new DsaDigestSigner(new ECDsaSigner(), digest); + verifier.Init(false, GetPubKeyEC()); + + return new BcTls13Verifier(verifier); + } + + case SignatureScheme.ed25519: + { + Ed25519Signer verifier = new Ed25519Signer(); + verifier.Init(false, GetPubKeyEd25519()); + + return new BcTls13Verifier(verifier); + } + + case SignatureScheme.ed448: + { + Ed448Signer verifier = new Ed448Signer(TlsUtilities.EmptyBytes); + verifier.Init(false, GetPubKeyEd448()); + + return new BcTls13Verifier(verifier); + } + + case SignatureScheme.rsa_pkcs1_sha1: + case SignatureScheme.rsa_pkcs1_sha256: + case SignatureScheme.rsa_pkcs1_sha384: + case SignatureScheme.rsa_pkcs1_sha512: + { + ValidateRsa_Pkcs1(); + + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + RsaDigestSigner verifier = new RsaDigestSigner(digest, + TlsCryptoUtilities.GetOidForHash(cryptoHashAlgorithm)); + verifier.Init(false, GetPubKeyRsa()); + + return new BcTls13Verifier(verifier); + } + + case SignatureScheme.rsa_pss_pss_sha256: + case SignatureScheme.rsa_pss_pss_sha384: + case SignatureScheme.rsa_pss_pss_sha512: + { + ValidateRsa_Pss_Pss(SignatureScheme.GetSignatureAlgorithm(signatureScheme)); + + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); + verifier.Init(false, GetPubKeyRsa()); + + return new BcTls13Verifier(verifier); + } + + case SignatureScheme.rsa_pss_rsae_sha256: + case SignatureScheme.rsa_pss_rsae_sha384: + case SignatureScheme.rsa_pss_rsae_sha512: + { + ValidateRsa_Pss_Rsae(); + + int cryptoHashAlgorithm = SignatureScheme.GetCryptoHashAlgorithm(signatureScheme); + IDigest digest = m_crypto.CreateDigest(cryptoHashAlgorithm); + + PssSigner verifier = new PssSigner(new RsaEngine(), digest, digest.GetDigestSize()); + verifier.Init(false, GetPubKeyRsa()); + + return new BcTls13Verifier(verifier); + } + + // TODO[RFC 8998] + //case SignatureScheme.sm2sig_sm3: + //{ + // ParametersWithID parametersWithID = new ParametersWithID(GetPubKeyEC(), + // Strings.ToByteArray("TLSv1.3+GM+Cipher+Suite")); + + // SM2Signer verifier = new SM2Signer(); + // verifier.Init(false, parametersWithID); + + // return new BcTls13Verifier(verifier); + //} + + default: + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } + + /// + public virtual byte[] GetEncoded() + { + return m_keyInfo.GetEncoded(Asn1Encodable.Der); + } + + /// + public virtual byte[] GetExtension(DerObjectIdentifier extensionOid) + { + return null; + } + + public virtual BigInteger SerialNumber => null; + + public virtual string SigAlgOid => null; + + public virtual Asn1Encodable GetSigAlgParams() => null; + + /// + public virtual short GetLegacySignatureAlgorithm() + { + AsymmetricKeyParameter publicKey = GetPublicKey(); + if (publicKey.IsPrivate) + throw new TlsFatalAlert(AlertDescription.internal_error); + + if (!SupportsKeyUsage(KeyUsage.DigitalSignature)) + return -1; + + /* + * RFC 5246 7.4.6. Client Certificate + */ + + /* + * RSA public key; the certificate MUST allow the key to be used for signing with the + * signature scheme and hash algorithm that will be employed in the certificate verify + * message. + */ + if (publicKey is RsaKeyParameters) + return SignatureAlgorithm.rsa; + + /* + * DSA public key; the certificate MUST allow the key to be used for signing with the + * hash algorithm that will be employed in the certificate verify message. + */ + if (publicKey is DsaPublicKeyParameters) + return SignatureAlgorithm.dsa; + + /* + * ECDSA-capable public key; the certificate MUST allow the key to be used for signing + * with the hash algorithm that will be employed in the certificate verify message; the + * public key MUST use a curve and point format supported by the server. + */ + if (publicKey is ECPublicKeyParameters) + { + // TODO Check the curve and point format + return SignatureAlgorithm.ecdsa; + } + + return -1; + } + + /// + public virtual DHPublicKeyParameters GetPubKeyDH() + { + try + { + return (DHPublicKeyParameters)GetPublicKey(); + } + catch (InvalidCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + /// + public virtual DsaPublicKeyParameters GetPubKeyDss() + { + try + { + return (DsaPublicKeyParameters)GetPublicKey(); + } + catch (InvalidCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + /// + public virtual ECPublicKeyParameters GetPubKeyEC() + { + try + { + return (ECPublicKeyParameters)GetPublicKey(); + } + catch (InvalidCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + /// + public virtual Ed25519PublicKeyParameters GetPubKeyEd25519() + { + try + { + return (Ed25519PublicKeyParameters)GetPublicKey(); + } + catch (InvalidCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + /// + public virtual Ed448PublicKeyParameters GetPubKeyEd448() + { + try + { + return (Ed448PublicKeyParameters)GetPublicKey(); + } + catch (InvalidCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + /// + public virtual RsaKeyParameters GetPubKeyRsa() + { + try + { + return (RsaKeyParameters)GetPublicKey(); + } + catch (InvalidCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + /// + public virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm) + { + return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.DigitalSignature); + } + + /// + public virtual bool SupportsSignatureAlgorithmCA(short signatureAlgorithm) + { + return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.KeyCertSign); + } + + /// + public virtual TlsCertificate CheckUsageInRole(int tlsCertificateRole) + { + switch (tlsCertificateRole) + { + case TlsCertificateRole.DH: + { + ValidateKeyUsage(KeyUsage.KeyAgreement); + this.m_pubKeyDH = GetPubKeyDH(); + return this; + } + case TlsCertificateRole.ECDH: + { + ValidateKeyUsage(KeyUsage.KeyAgreement); + this.m_pubKeyEC = GetPubKeyEC(); + return this; + } + } + + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + /// + protected virtual AsymmetricKeyParameter GetPublicKey() + { + try + { + return PublicKeyFactory.CreateKey(m_keyInfo); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); + } + } + + protected virtual bool SupportsKeyUsage(int keyUsageBits) + { + return true; + } + + protected virtual bool SupportsRsa_Pkcs1() + { + AlgorithmIdentifier pubKeyAlgID = m_keyInfo.AlgorithmID; + return RsaUtilities.SupportsPkcs1(pubKeyAlgID); + } + + protected virtual bool SupportsRsa_Pss_Pss(short signatureAlgorithm) + { + AlgorithmIdentifier pubKeyAlgID = m_keyInfo.AlgorithmID; + return RsaUtilities.SupportsPss_Pss(signatureAlgorithm, pubKeyAlgID); + } + + protected virtual bool SupportsRsa_Pss_Rsae() + { + AlgorithmIdentifier pubKeyAlgID = m_keyInfo.AlgorithmID; + return RsaUtilities.SupportsPss_Rsae(pubKeyAlgID); + } + + /// + protected virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm, int keyUsage) + { + if (!SupportsKeyUsage(keyUsage)) + return false; + + AsymmetricKeyParameter publicKey = GetPublicKey(); + + switch (signatureAlgorithm) + { + case SignatureAlgorithm.rsa: + return SupportsRsa_Pkcs1() + && publicKey is RsaKeyParameters; + + case SignatureAlgorithm.dsa: + return publicKey is DsaPublicKeyParameters; + + case SignatureAlgorithm.ecdsa: + case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: + case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: + case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: + return publicKey is ECPublicKeyParameters; + + case SignatureAlgorithm.ed25519: + return publicKey is Ed25519PublicKeyParameters; + + case SignatureAlgorithm.ed448: + return publicKey is Ed448PublicKeyParameters; + + case SignatureAlgorithm.rsa_pss_rsae_sha256: + case SignatureAlgorithm.rsa_pss_rsae_sha384: + case SignatureAlgorithm.rsa_pss_rsae_sha512: + return SupportsRsa_Pss_Rsae() + && publicKey is RsaKeyParameters; + + case SignatureAlgorithm.rsa_pss_pss_sha256: + case SignatureAlgorithm.rsa_pss_pss_sha384: + case SignatureAlgorithm.rsa_pss_pss_sha512: + return SupportsRsa_Pss_Pss(signatureAlgorithm) + && publicKey is RsaKeyParameters; + + default: + return false; + } + } + + /// + public virtual void ValidateKeyUsage(int keyUsageBits) + { + if (!SupportsKeyUsage(keyUsageBits)) + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + /// + protected virtual void ValidateRsa_Pkcs1() + { + if (!SupportsRsa_Pkcs1()) + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + /// + protected virtual void ValidateRsa_Pss_Pss(short signatureAlgorithm) + { + if (!SupportsRsa_Pss_Pss(signatureAlgorithm)) + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + + /// + protected virtual void ValidateRsa_Pss_Rsae() + { + if (!SupportsRsa_Pss_Rsae()) + throw new TlsFatalAlert(AlertDescription.certificate_unknown); + } + } +} -- cgit 1.4.1