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;
/// <returns><c>true</c> if this certificate chain contains no certificates, or <c>false</c> otherwise.
/// </returns>
- public bool IsEmpty
- {
- get { return m_certificateEntryList.Length == 0; }
- }
+ public bool IsEmpty => m_certificateEntryList.Length == 0;
/// <summary>Encode this <see cref="Certificate"/> to a <see cref="Stream"/>, and optionally calculate the
/// "end point hash" (per RFC 5929's tls-server-end-point binding).</summary>
@@ -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);
}
/// <exception cref="IOException"/>
@@ -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);
}
/// <exception cref="IOException"/>
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);
}
/// <exception cref="IOException"/>
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
}
/// <exception cref="IOException"/>
- public static short GetClientCertificateTypeExtensionServer(IDictionary<int, byte[]> extensions)
+ public static short GetClientCertificateTypeExtensionServer(IDictionary<int, byte[]> 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);
}
/// <exception cref="IOException"/>
@@ -415,10 +416,11 @@ namespace Org.BouncyCastle.Tls
}
/// <exception cref="IOException"/>
- public static short GetServerCertificateTypeExtensionServer(IDictionary<int, byte[]> extensions)
+ public static short GetServerCertificateTypeExtensionServer(IDictionary<int, byte[]> 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);
}
/// <exception cref="IOException"/>
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<int, byte[]> 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<int, byte[]> 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
/// <exception cref="IOException">if there is an issue on decoding or constructing the certificate.</exception>
TlsCertificate CreateCertificate(byte[] encoding);
+ /// <summary>Create a TlsCertificate from an ASN.1 binary encoding of a certificate.</summary>
+ /// <param name="type">Certificate type as per IANA TLS Certificate Types registry.</param>
+ /// <param name="encoding">DER/BER encoding of the certificate of interest.</param>
+ /// <returns>a TlsCertificate.</returns>
+ /// <exception cref="IOException">if there is an issue on decoding or constructing the certificate.</exception>
+ TlsCertificate CreateCertificate(short type, byte[] encoding);
+
/// <summary>Create a cipher for the specified encryption and MAC algorithms.</summary>
/// <remarks>
/// See enumeration classes <see cref="EncryptionAlgorithm"/>, <see cref="MacAlgorithm"/> 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
{
/// <summary>Implementation class for a single X.509 certificate based on the BC light-weight API.</summary>
public class BcTlsCertificate
- : TlsCertificate
+ : BcTlsRawKeyCertificate
{
/// <exception cref="IOException"/>
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;
-
/// <exception cref="IOException"/>
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;
}
- /// <exception cref="IOException"/>
- 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;
/// <exception cref="IOException"/>
- 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);
- }
- }
-
- /// <exception cref="IOException"/>
- 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; }
- }
-
- /// <exception cref="IOException"/>
- public virtual byte[] GetEncoded()
+ public override byte[] GetEncoded()
{
return m_certificate.GetEncoded(Asn1Encodable.Der);
}
/// <exception cref="IOException"/>
- 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;
- }
-
- /// <exception cref="IOException"/>
- 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;
- }
-
- /// <exception cref="IOException"/>
- public virtual DHPublicKeyParameters GetPubKeyDH()
- {
- try
- {
- return (DHPublicKeyParameters)GetPublicKey();
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual DsaPublicKeyParameters GetPubKeyDss()
- {
- try
- {
- return (DsaPublicKeyParameters)GetPublicKey();
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual ECPublicKeyParameters GetPubKeyEC()
- {
- try
- {
- return (ECPublicKeyParameters)GetPublicKey();
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual Ed25519PublicKeyParameters GetPubKeyEd25519()
- {
- try
- {
- return (Ed25519PublicKeyParameters)GetPublicKey();
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual Ed448PublicKeyParameters GetPubKeyEd448()
- {
- try
- {
- return (Ed448PublicKeyParameters)GetPublicKey();
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual RsaKeyParameters GetPubKeyRsa()
- {
- try
- {
- return (RsaKeyParameters)GetPublicKey();
- }
- catch (InvalidCastException e)
- {
- throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm)
- {
- return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.DigitalSignature);
- }
-
- /// <exception cref="IOException"/>
- public virtual bool SupportsSignatureAlgorithmCA(short signatureAlgorithm)
- {
- return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.KeyCertSign);
- }
-
- /// <exception cref="IOException"/>
- 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);
- }
-
- /// <exception cref="IOException"/>
- 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);
- }
-
- /// <exception cref="IOException"/>
- 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;
- }
- }
-
- /// <exception cref="IOException"/>
- public virtual void ValidateKeyUsage(int keyUsageBits)
- {
- if (!SupportsKeyUsage(keyUsageBits))
- throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- }
-
- /// <exception cref="IOException"/>
- protected virtual void ValidateRsa_Pkcs1()
- {
- if (!SupportsRsa_Pkcs1())
- throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- }
-
- /// <exception cref="IOException"/>
- protected virtual void ValidateRsa_Pss_Pss(short signatureAlgorithm)
- {
- if (!SupportsRsa_Pss_Pss(signatureAlgorithm))
- throw new TlsFatalAlert(AlertDescription.certificate_unknown);
- }
-
- /// <exception cref="IOException"/>
- 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
+{
+ /// <summary>Implementation class for a single X.509 certificate based on the BC light-weight API.</summary>
+ 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;
+
+ /// <exception cref="IOException"/>
+ 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;
+
+ /// <exception cref="IOException"/>
+ 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);
+ }
+
+ /// <exception cref="IOException"/>
+ 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);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ 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);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual byte[] GetEncoded()
+ {
+ return m_keyInfo.GetEncoded(Asn1Encodable.Der);
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual byte[] GetExtension(DerObjectIdentifier extensionOid)
+ {
+ return null;
+ }
+
+ public virtual BigInteger SerialNumber => null;
+
+ public virtual string SigAlgOid => null;
+
+ public virtual Asn1Encodable GetSigAlgParams() => null;
+
+ /// <exception cref="IOException"/>
+ 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;
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual DHPublicKeyParameters GetPubKeyDH()
+ {
+ try
+ {
+ return (DHPublicKeyParameters)GetPublicKey();
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual DsaPublicKeyParameters GetPubKeyDss()
+ {
+ try
+ {
+ return (DsaPublicKeyParameters)GetPublicKey();
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual ECPublicKeyParameters GetPubKeyEC()
+ {
+ try
+ {
+ return (ECPublicKeyParameters)GetPublicKey();
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual Ed25519PublicKeyParameters GetPubKeyEd25519()
+ {
+ try
+ {
+ return (Ed25519PublicKeyParameters)GetPublicKey();
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual Ed448PublicKeyParameters GetPubKeyEd448()
+ {
+ try
+ {
+ return (Ed448PublicKeyParameters)GetPublicKey();
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual RsaKeyParameters GetPubKeyRsa()
+ {
+ try
+ {
+ return (RsaKeyParameters)GetPublicKey();
+ }
+ catch (InvalidCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm)
+ {
+ return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.DigitalSignature);
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual bool SupportsSignatureAlgorithmCA(short signatureAlgorithm)
+ {
+ return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.KeyCertSign);
+ }
+
+ /// <exception cref="IOException"/>
+ 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);
+ }
+
+ /// <exception cref="IOException"/>
+ 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);
+ }
+
+ /// <exception cref="IOException"/>
+ 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;
+ }
+ }
+
+ /// <exception cref="IOException"/>
+ public virtual void ValidateKeyUsage(int keyUsageBits)
+ {
+ if (!SupportsKeyUsage(keyUsageBits))
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ /// <exception cref="IOException"/>
+ protected virtual void ValidateRsa_Pkcs1()
+ {
+ if (!SupportsRsa_Pkcs1())
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ /// <exception cref="IOException"/>
+ protected virtual void ValidateRsa_Pss_Pss(short signatureAlgorithm)
+ {
+ if (!SupportsRsa_Pss_Pss(signatureAlgorithm))
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ /// <exception cref="IOException"/>
+ protected virtual void ValidateRsa_Pss_Rsae()
+ {
+ if (!SupportsRsa_Pss_Rsae())
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+ }
+}
|