diff --git a/crypto/src/crypto/tls/CertChainType.cs b/crypto/src/crypto/tls/CertChainType.cs
index b526a79a7..cbb183441 100644
--- a/crypto/src/crypto/tls/CertChainType.cs
+++ b/crypto/src/crypto/tls/CertChainType.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public abstract class CertChainType
{
- public const short individual_certs = 0;
- public const short pkipath = 1;
+ public const byte individual_certs = 0;
+ public const byte pkipath = 1;
- public static bool IsValid(short certChainType)
+ public static bool IsValid(byte certChainType)
{
return certChainType >= individual_certs && certChainType <= pkipath;
}
diff --git a/crypto/src/crypto/tls/CertificateStatusType.cs b/crypto/src/crypto/tls/CertificateStatusType.cs
index 222d31635..54b741b42 100644
--- a/crypto/src/crypto/tls/CertificateStatusType.cs
+++ b/crypto/src/crypto/tls/CertificateStatusType.cs
@@ -7,6 +7,6 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 3546 3.6
*/
- public const short ocsp = 1;
+ public const byte ocsp = 1;
}
}
diff --git a/crypto/src/crypto/tls/ChangeCipherSpec.cs b/crypto/src/crypto/tls/ChangeCipherSpec.cs
index 2ef4c3b34..323de9162 100644
--- a/crypto/src/crypto/tls/ChangeCipherSpec.cs
+++ b/crypto/src/crypto/tls/ChangeCipherSpec.cs
@@ -4,6 +4,6 @@ namespace Org.BouncyCastle.Crypto.Tls
{
public abstract class ChangeCipherSpec
{
- public const short change_cipher_spec = 1;
+ public const byte change_cipher_spec = 1;
}
}
diff --git a/crypto/src/crypto/tls/ClientAuthenticationType.cs b/crypto/src/crypto/tls/ClientAuthenticationType.cs
index 51e6e5005..dd248f3df 100644
--- a/crypto/src/crypto/tls/ClientAuthenticationType.cs
+++ b/crypto/src/crypto/tls/ClientAuthenticationType.cs
@@ -7,8 +7,8 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 5077 4
*/
- public const short anonymous = 0;
- public const short certificate_based = 1;
- public const short psk = 2;
+ public const byte anonymous = 0;
+ public const byte certificate_based = 1;
+ public const byte psk = 2;
}
}
diff --git a/crypto/src/crypto/tls/ECBasisType.cs b/crypto/src/crypto/tls/ECBasisType.cs
index b7c9c6bd7..5416e17c0 100644
--- a/crypto/src/crypto/tls/ECBasisType.cs
+++ b/crypto/src/crypto/tls/ECBasisType.cs
@@ -5,10 +5,10 @@ namespace Org.BouncyCastle.Crypto.Tls
/// <summary>RFC 4492 5.4. (Errata ID: 2389)</summary>
public abstract class ECBasisType
{
- public const short ec_basis_trinomial = 1;
- public const short ec_basis_pentanomial = 2;
+ public const byte ec_basis_trinomial = 1;
+ public const byte ec_basis_pentanomial = 2;
- public static bool IsValid(short ecBasisType)
+ public static bool IsValid(byte ecBasisType)
{
return ecBasisType >= ec_basis_trinomial && ecBasisType <= ec_basis_pentanomial;
}
diff --git a/crypto/src/crypto/tls/HeartbeatMessageType.cs b/crypto/src/crypto/tls/HeartbeatMessageType.cs
index 9e3ad213c..57a4b86be 100644
--- a/crypto/src/crypto/tls/HeartbeatMessageType.cs
+++ b/crypto/src/crypto/tls/HeartbeatMessageType.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public abstract class HeartbeatMessageType
{
- public const short heartbeat_request = 1;
- public const short heartbeat_response = 2;
+ public const byte heartbeat_request = 1;
+ public const byte heartbeat_response = 2;
- public static bool IsValid(short heartbeatMessageType)
+ public static bool IsValid(byte heartbeatMessageType)
{
return heartbeatMessageType >= heartbeat_request && heartbeatMessageType <= heartbeat_response;
}
diff --git a/crypto/src/crypto/tls/HeartbeatMode.cs b/crypto/src/crypto/tls/HeartbeatMode.cs
index 0968f6e10..f1570a84d 100644
--- a/crypto/src/crypto/tls/HeartbeatMode.cs
+++ b/crypto/src/crypto/tls/HeartbeatMode.cs
@@ -7,10 +7,10 @@ namespace Org.BouncyCastle.Crypto.Tls
*/
public abstract class HeartbeatMode
{
- public const short peer_allowed_to_send = 1;
- public const short peer_not_allowed_to_send = 2;
+ public const byte peer_allowed_to_send = 1;
+ public const byte peer_not_allowed_to_send = 2;
- public static bool IsValid(short heartbeatMode)
+ public static bool IsValid(byte heartbeatMode)
{
return heartbeatMode >= peer_allowed_to_send && heartbeatMode <= peer_not_allowed_to_send;
}
diff --git a/crypto/src/crypto/tls/MaxFragmentLength.cs b/crypto/src/crypto/tls/MaxFragmentLength.cs
index adb6d129c..5b10b35dd 100644
--- a/crypto/src/crypto/tls/MaxFragmentLength.cs
+++ b/crypto/src/crypto/tls/MaxFragmentLength.cs
@@ -7,12 +7,12 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 3546 3.2.
*/
- public const short pow2_9 = 1;
- public const short pow2_10 = 2;
- public const short pow2_11 = 3;
- public const short pow2_12 = 4;
+ public const byte pow2_9 = 1;
+ public const byte pow2_10 = 2;
+ public const byte pow2_11 = 3;
+ public const byte pow2_12 = 4;
- public static bool IsValid(short maxFragmentLength)
+ public static bool IsValid(byte maxFragmentLength)
{
return maxFragmentLength >= pow2_9 && maxFragmentLength <= pow2_12;
}
diff --git a/crypto/src/crypto/tls/NameType.cs b/crypto/src/crypto/tls/NameType.cs
index ffcb639d0..25f6046fc 100644
--- a/crypto/src/crypto/tls/NameType.cs
+++ b/crypto/src/crypto/tls/NameType.cs
@@ -7,6 +7,6 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 3546 3.1.
*/
- public const short host_name = 0;
+ public const byte host_name = 0;
}
}
diff --git a/crypto/src/crypto/tls/NamedCurve.cs b/crypto/src/crypto/tls/NamedCurve.cs
index 8ef395069..b8aa0ecde 100644
--- a/crypto/src/crypto/tls/NamedCurve.cs
+++ b/crypto/src/crypto/tls/NamedCurve.cs
@@ -58,7 +58,8 @@ namespace Org.BouncyCastle.Crypto.Tls
public static bool IsValid(int namedCurve)
{
- return namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1;
+ return (namedCurve >= sect163k1 && namedCurve <= brainpoolP512r1)
+ || (namedCurve >= arbitrary_explicit_prime_curves && namedCurve <= arbitrary_explicit_char2_curves);
}
public static bool RefersToASpecificNamedCurve(int namedCurve)
@@ -73,24 +74,4 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
}
-
- internal class NamedCurveHelper
- {
- internal static ECDomainParameters GetECParameters(int namedCurve)
- {
- if (!NamedCurve.IsValid(namedCurve))
- return null;
-
- string curveName = namedCurve.ToString();
-
- // Lazily created the first time a particular curve is accessed
- X9ECParameters ecP = SecNamedCurves.GetByName(curveName);
-
- if (ecP == null)
- return null;
-
- // It's a bit inefficient to do this conversion every time
- return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
- }
- }
}
diff --git a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
index a671ebfbe..a36bff75b 100644
--- a/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
+++ b/crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Tls
// TODO Check namedCurve is one we offered?
- curve_params = NamedCurveHelper.GetECParameters(namedCurve);
+ curve_params = TlsEccUtilities.GetParametersForNamedCurve(namedCurve);
}
else
{
diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs
new file mode 100644
index 000000000..a306fdb45
--- /dev/null
+++ b/crypto/src/crypto/tls/TlsEccUtilities.cs
@@ -0,0 +1,644 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.EC;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Math.Field;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+ public class TlsEccUtilities
+ {
+ private static readonly string[] curveNames = new string[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
+ "sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
+ "sect571k1", "sect571r1", "secp160k1", "secp160r1", "secp160r2", "secp192k1", "secp192r1", "secp224k1",
+ "secp224r1", "secp256k1", "secp256r1", "secp384r1", "secp521r1",
+ "brainpoolP256r1", "brainpoolP384r1", "brainpoolP512r1"};
+
+ public static void AddSupportedEllipticCurvesExtension(Hashtable extensions, int[] namedCurves)
+ {
+ extensions[ExtensionType.elliptic_curves] = CreateSupportedEllipticCurvesExtension(namedCurves);
+ }
+
+ public static void AddSupportedPointFormatsExtension(Hashtable extensions, byte[] ecPointFormats)
+ {
+ extensions[ExtensionType.ec_point_formats] = CreateSupportedPointFormatsExtension(ecPointFormats);
+ }
+
+ public static int[] GetSupportedEllipticCurvesExtension(Hashtable extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.elliptic_curves);
+ return extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData);
+ }
+
+ public static byte[] GetSupportedPointFormatsExtension(Hashtable extensions)
+ {
+ byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats);
+ return extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData);
+ }
+
+ public static byte[] CreateSupportedEllipticCurvesExtension(int[] namedCurves)
+ {
+ if (namedCurves == null || namedCurves.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+
+ return TlsUtilities.EncodeUint16ArrayWithUint16Length(namedCurves);
+ }
+
+ public static byte[] CreateSupportedPointFormatsExtension(byte[] ecPointFormats)
+ {
+ if (ecPointFormats == null || !Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+ {
+ /*
+ * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+ * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+ */
+
+ // NOTE: We add it at the end (lowest preference)
+ ecPointFormats = Arrays.Append(ecPointFormats, ECPointFormat.uncompressed);
+ }
+
+ return TlsUtilities.EncodeUint8ArrayWithUint8Length(ecPointFormats);
+ }
+
+ public static int[] ReadSupportedEllipticCurvesExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ int length = TlsUtilities.ReadUint16(buf);
+ if (length < 2 || (length & 1) != 0)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ int[] namedCurves = TlsUtilities.ReadUint16Array(length / 2, buf);
+
+ TlsProtocolHandler.AssertEmpty(buf);
+
+ return namedCurves;
+ }
+
+ public static byte[] ReadSupportedPointFormatsExtension(byte[] extensionData)
+ {
+ if (extensionData == null)
+ throw new ArgumentNullException("extensionData");
+
+ MemoryStream buf = new MemoryStream(extensionData, false);
+
+ byte length = TlsUtilities.ReadUint8(buf);
+ if (length < 1)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+
+ byte[] ecPointFormats = TlsUtilities.ReadUint8Array(length, buf);
+
+ TlsProtocolHandler.AssertEmpty(buf);
+
+ if (!Arrays.Contains(ecPointFormats, ECPointFormat.uncompressed))
+ {
+ /*
+ * RFC 4492 5.1. If the Supported Point Formats Extension is indeed sent, it MUST
+ * contain the value 0 (uncompressed) as one of the items in the list of point formats.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ return ecPointFormats;
+ }
+
+ public static string GetNameOfNamedCurve(int namedCurve)
+ {
+ return IsSupportedNamedCurve(namedCurve) ? curveNames[namedCurve - 1] : null;
+ }
+
+ public static ECDomainParameters GetParametersForNamedCurve(int namedCurve)
+ {
+ string curveName = GetNameOfNamedCurve(namedCurve);
+ if (curveName == null)
+ return null;
+
+ // Parameters are lazily created the first time a particular curve is accessed
+
+ X9ECParameters ecP = CustomNamedCurves.GetByName(curveName);
+ if (ecP == null)
+ {
+ ecP = ECNamedCurveTable.GetByName(curveName);
+ if (ecP == null)
+ return null;
+ }
+
+ // It's a bit inefficient to do this conversion every time
+ return new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());
+ }
+
+ public static bool HasAnySupportedNamedCurves()
+ {
+ return curveNames.Length > 0;
+ }
+
+ public static bool ContainsEccCipherSuites(int[] cipherSuites)
+ {
+ for (int i = 0; i < cipherSuites.Length; ++i)
+ {
+ if (IsEccCipherSuite(cipherSuites[i]))
+ return true;
+ }
+ return false;
+ }
+
+ public static bool IsEccCipherSuite(int cipherSuite)
+ {
+ switch (cipherSuite)
+ {
+ /*
+ * RFC 4492
+ */
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+
+ /*
+ * RFC 5289
+ */
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+
+ /*
+ * RFC 5489
+ */
+ case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+ case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+
+ ///*
+ // * RFC 6367
+ // */
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ //case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+ //case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+ //case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+ //case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ //case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+ //case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+ //case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+ //case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+
+ //case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+ //case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+
+ ///*
+ // * draft-agl-tls-chacha20poly1305-04
+ // */
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+
+ ///*
+ // * draft-josefsson-salsa20-tls-04
+ // */
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+ //case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+ //case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+ //case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+ //case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b)
+ {
+ // TODO Move to ECDomainParameters.Equals() or other utility method?
+ return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H);
+ }
+
+ public static bool IsSupportedNamedCurve(int namedCurve)
+ {
+ return (namedCurve > 0 && namedCurve <= curveNames.Length);
+ }
+
+ public static bool IsCompressionPreferred(byte[] ecPointFormats, byte compressionFormat)
+ {
+ if (ecPointFormats == null)
+ return false;
+
+ for (int i = 0; i < ecPointFormats.Length; ++i)
+ {
+ byte ecPointFormat = ecPointFormats[i];
+ if (ecPointFormat == ECPointFormat.uncompressed)
+ return false;
+ if (ecPointFormat == compressionFormat)
+ return true;
+ }
+ return false;
+ }
+
+ public static byte[] SerializeECFieldElement(int fieldSize, BigInteger x)
+ {
+ return BigIntegers.AsUnsignedByteArray((fieldSize + 7) / 8, x);
+ }
+
+ public static byte[] SerializeECPoint(byte[] ecPointFormats, ECPoint point)
+ {
+ ECCurve curve = point.Curve;
+
+ /*
+ * RFC 4492 5.7. ...an elliptic curve point in uncompressed or compressed format. Here, the
+ * format MUST conform to what the server has requested through a Supported Point Formats
+ * Extension if this extension was used, and MUST be uncompressed if this extension was not
+ * used.
+ */
+ bool compressed = false;
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_prime);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ compressed = IsCompressionPreferred(ecPointFormats, ECPointFormat.ansiX962_compressed_char2);
+ }
+ return point.GetEncoded(compressed);
+ }
+
+ public static byte[] SerializeECPublicKey(byte[] ecPointFormats, ECPublicKeyParameters keyParameters)
+ {
+ return SerializeECPoint(ecPointFormats, keyParameters.Q);
+ }
+
+ public static BigInteger DeserializeECFieldElement(int fieldSize, byte[] encoding)
+ {
+ int requiredLength = (fieldSize + 7) / 8;
+ if (encoding.Length != requiredLength)
+ throw new TlsFatalAlert(AlertDescription.decode_error);
+ return new BigInteger(1, encoding);
+ }
+
+ public static ECPoint DeserializeECPoint(byte[] ecPointFormats, ECCurve curve, byte[] encoding)
+ {
+ if (encoding == null || encoding.Length < 1)
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ byte actualFormat;
+ switch (encoding[0])
+ {
+ case 0x02: // compressed
+ case 0x03: // compressed
+ {
+ if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ actualFormat = ECPointFormat.ansiX962_compressed_char2;
+ }
+ else if (ECAlgorithms.IsFpCurve(curve))
+ {
+ actualFormat = ECPointFormat.ansiX962_compressed_prime;
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ break;
+ }
+ case 0x04: // uncompressed
+ {
+ actualFormat = ECPointFormat.uncompressed;
+ break;
+ }
+ case 0x00: // infinity
+ case 0x06: // hybrid
+ case 0x07: // hybrid
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ if (!Arrays.Contains(ecPointFormats, actualFormat))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ return curve.DecodePoint(encoding);
+ }
+
+ public static ECPublicKeyParameters DeserializeECPublicKey(byte[] ecPointFormats, ECDomainParameters curve_params,
+ byte[] encoding)
+ {
+ try
+ {
+ ECPoint Y = DeserializeECPoint(ecPointFormats, curve_params.Curve, encoding);
+ return new ECPublicKeyParameters(Y, curve_params);
+ }
+ catch (Exception)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public static byte[] CalculateECDHBasicAgreement(ECPublicKeyParameters publicKey, ECPrivateKeyParameters privateKey)
+ {
+ ECDHBasicAgreement basicAgreement = new ECDHBasicAgreement();
+ basicAgreement.Init(privateKey);
+ BigInteger agreementValue = basicAgreement.CalculateAgreement(publicKey);
+
+ /*
+ * RFC 4492 5.10. Note that this octet string (Z in IEEE 1363 terminology) as output by
+ * FE2OSP, the Field Element to Octet String Conversion Primitive, has constant length for
+ * any given field; leading zeros found in this octet string MUST NOT be truncated.
+ */
+ return BigIntegers.AsUnsignedByteArray(basicAgreement.GetFieldSize(), agreementValue);
+ }
+
+ public static AsymmetricCipherKeyPair GenerateECKeyPair(SecureRandom random, ECDomainParameters ecParams)
+ {
+ ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
+ keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random));
+ return keyPairGenerator.GenerateKeyPair();
+ }
+
+ public static ECPrivateKeyParameters GenerateEphemeralClientKeyExchange(SecureRandom random, byte[] ecPointFormats,
+ ECDomainParameters ecParams, Stream output)
+ {
+ AsymmetricCipherKeyPair kp = TlsEccUtilities.GenerateECKeyPair(random, ecParams);
+
+ ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)kp.Public;
+ WriteECPoint(ecPointFormats, ecPublicKey.Q, output);
+
+ return (ECPrivateKeyParameters)kp.Private;
+ }
+
+ public static ECPublicKeyParameters ValidateECPublicKey(ECPublicKeyParameters key)
+ {
+ // TODO Check RFC 4492 for validation
+ return key;
+ }
+
+ public static int ReadECExponent(int fieldSize, Stream input)
+ {
+ BigInteger K = ReadECParameter(input);
+ if (K.BitLength < 32)
+ {
+ int k = K.IntValue;
+ if (k > 0 && k < fieldSize)
+ {
+ return k;
+ }
+ }
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ public static BigInteger ReadECFieldElement(int fieldSize, Stream input)
+ {
+ return DeserializeECFieldElement(fieldSize, TlsUtilities.ReadOpaque8(input));
+ }
+
+ public static BigInteger ReadECParameter(Stream input)
+ {
+ // TODO Are leading zeroes okay here?
+ return new BigInteger(1, TlsUtilities.ReadOpaque8(input));
+ }
+
+ public static ECDomainParameters ReadECParameters(int[] namedCurves, byte[] ecPointFormats, Stream input)
+ {
+ try
+ {
+ byte curveType = TlsUtilities.ReadUint8(input);
+
+ switch (curveType)
+ {
+ case ECCurveType.explicit_prime:
+ {
+ CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_prime_curves);
+
+ BigInteger prime_p = ReadECParameter(input);
+ BigInteger a = ReadECFieldElement(prime_p.BitLength, input);
+ BigInteger b = ReadECFieldElement(prime_p.BitLength, input);
+ byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+ BigInteger order = ReadECParameter(input);
+ BigInteger cofactor = ReadECParameter(input);
+ ECCurve curve = new FpCurve(prime_p, a, b, order, cofactor);
+ ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+ return new ECDomainParameters(curve, basePoint, order, cofactor);
+ }
+ case ECCurveType.explicit_char2:
+ {
+ CheckNamedCurve(namedCurves, NamedCurve.arbitrary_explicit_char2_curves);
+
+ int m = TlsUtilities.ReadUint16(input);
+ byte basis = TlsUtilities.ReadUint8(input);
+ if (!ECBasisType.IsValid(basis))
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+
+ int k1 = ReadECExponent(m, input), k2 = -1, k3 = -1;
+ if (basis == ECBasisType.ec_basis_pentanomial)
+ {
+ k2 = ReadECExponent(m, input);
+ k3 = ReadECExponent(m, input);
+ }
+
+ BigInteger a = ReadECFieldElement(m, input);
+ BigInteger b = ReadECFieldElement(m, input);
+ byte[] baseEncoding = TlsUtilities.ReadOpaque8(input);
+ BigInteger order = ReadECParameter(input);
+ BigInteger cofactor = ReadECParameter(input);
+
+ ECCurve curve = (basis == ECBasisType.ec_basis_pentanomial)
+ ? new F2mCurve(m, k1, k2, k3, a, b, order, cofactor)
+ : new F2mCurve(m, k1, a, b, order, cofactor);
+
+ ECPoint basePoint = DeserializeECPoint(ecPointFormats, curve, baseEncoding);
+
+ return new ECDomainParameters(curve, basePoint, order, cofactor);
+ }
+ case ECCurveType.named_curve:
+ {
+ int namedCurve = TlsUtilities.ReadUint16(input);
+ if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+ {
+ /*
+ * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a
+ * specific curve. Values of NamedCurve that indicate support for a class of
+ * explicitly defined curves are not allowed here [...].
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
+ CheckNamedCurve(namedCurves, namedCurve);
+
+ return GetParametersForNamedCurve(namedCurve);
+ }
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ catch (Exception)
+ {
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ private static void CheckNamedCurve(int[] namedCurves, int namedCurve)
+ {
+ if (namedCurves != null && !Arrays.Contains(namedCurves, namedCurve))
+ {
+ /*
+ * RFC 4492 4. [...] servers MUST NOT negotiate the use of an ECC cipher suite
+ * unless they can complete the handshake while respecting the choice of curves
+ * and compression techniques specified by the client.
+ */
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+
+ public static void WriteECExponent(int k, Stream output)
+ {
+ BigInteger K = BigInteger.ValueOf(k);
+ WriteECParameter(K, output);
+ }
+
+ public static void WriteECFieldElement(ECFieldElement x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(x.GetEncoded(), output);
+ }
+
+ public static void WriteECFieldElement(int fieldSize, BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(SerializeECFieldElement(fieldSize, x), output);
+ }
+
+ public static void WriteECParameter(BigInteger x, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(BigIntegers.AsUnsignedByteArray(x), output);
+ }
+
+ public static void WriteExplicitECParameters(byte[] ecPointFormats, ECDomainParameters ecParameters,
+ Stream output)
+ {
+ ECCurve curve = ecParameters.Curve;
+
+ if (ECAlgorithms.IsFpCurve(curve))
+ {
+ TlsUtilities.WriteUint8(ECCurveType.explicit_prime, output);
+
+ WriteECParameter(curve.Field.Characteristic, output);
+ }
+ else if (ECAlgorithms.IsF2mCurve(curve))
+ {
+ IPolynomialExtensionField field = (IPolynomialExtensionField)curve.Field;
+ int[] exponents = field.MinimalPolynomial.GetExponentsPresent();
+
+ TlsUtilities.WriteUint8(ECCurveType.explicit_char2, output);
+
+ int m = exponents[exponents.Length - 1];
+ TlsUtilities.CheckUint16(m);
+ TlsUtilities.WriteUint16(m, output);
+
+ if (exponents.Length == 3)
+ {
+ TlsUtilities.WriteUint8(ECBasisType.ec_basis_trinomial, output);
+ WriteECExponent(exponents[1], output);
+ }
+ else if (exponents.Length == 5)
+ {
+ TlsUtilities.WriteUint8(ECBasisType.ec_basis_pentanomial, output);
+ WriteECExponent(exponents[1], output);
+ WriteECExponent(exponents[2], output);
+ WriteECExponent(exponents[3], output);
+ }
+ else
+ {
+ throw new ArgumentException("Only trinomial and pentomial curves are supported");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("'ecParameters' not a known curve type");
+ }
+
+ WriteECFieldElement(curve.A, output);
+ WriteECFieldElement(curve.B, output);
+ TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, ecParameters.G), output);
+ WriteECParameter(ecParameters.N, output);
+ WriteECParameter(ecParameters.H, output);
+ }
+
+ public static void WriteECPoint(byte[] ecPointFormats, ECPoint point, Stream output)
+ {
+ TlsUtilities.WriteOpaque8(SerializeECPoint(ecPointFormats, point), output);
+ }
+
+ public static void WriteNamedECParameters(int namedCurve, Stream output)
+ {
+ if (!NamedCurve.RefersToASpecificNamedCurve(namedCurve))
+ {
+ /*
+ * RFC 4492 5.4. All those values of NamedCurve are allowed that refer to a specific
+ * curve. Values of NamedCurve that indicate support for a class of explicitly defined
+ * curves are not allowed here [...].
+ */
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ TlsUtilities.WriteUint8(ECCurveType.named_curve, output);
+ TlsUtilities.CheckUint16(namedCurve);
+ TlsUtilities.WriteUint16(namedCurve, output);
+ }
+ }
+}
diff --git a/crypto/src/crypto/tls/TlsProtocolHandler.cs b/crypto/src/crypto/tls/TlsProtocolHandler.cs
index 4707df3b5..d40e179aa 100644
--- a/crypto/src/crypto/tls/TlsProtocolHandler.cs
+++ b/crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -1166,7 +1166,7 @@ namespace Org.BouncyCastle.Crypto.Tls
* @param is The Stream to check.
* @throws IOException If is is not empty.
*/
- internal void AssertEmpty(
+ protected internal static void AssertEmpty(
MemoryStream inStr)
{
if (inStr.Position < inStr.Length)
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 2309fc3da..644d079c1 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -52,43 +52,43 @@ namespace Org.BouncyCastle.Crypto.Tls
return (i & 0xFFFFFF) == i;
}
- internal static void WriteUint8(byte i, Stream os)
+ public static void WriteUint8(byte i, Stream os)
{
os.WriteByte(i);
}
- internal static void WriteUint8(byte i, byte[] buf, int offset)
+ public static void WriteUint8(byte i, byte[] buf, int offset)
{
buf[offset] = i;
}
- internal static void WriteUint16(int i, Stream os)
+ public static void WriteUint16(int i, Stream os)
{
os.WriteByte((byte)(i >> 8));
os.WriteByte((byte)i);
}
- internal static void WriteUint16(int i, byte[] buf, int offset)
+ public static void WriteUint16(int i, byte[] buf, int offset)
{
buf[offset] = (byte)(i >> 8);
buf[offset + 1] = (byte)i;
}
- internal static void WriteUint24(int i, Stream os)
+ public static void WriteUint24(int i, Stream os)
{
os.WriteByte((byte)(i >> 16));
os.WriteByte((byte)(i >> 8));
os.WriteByte((byte)i);
}
- internal static void WriteUint24(int i, byte[] buf, int offset)
+ public static void WriteUint24(int i, byte[] buf, int offset)
{
buf[offset] = (byte)(i >> 16);
buf[offset + 1] = (byte)(i >> 8);
buf[offset + 2] = (byte)(i);
}
- internal static void WriteUint64(long i, Stream os)
+ public static void WriteUint64(long i, Stream os)
{
os.WriteByte((byte)(i >> 56));
os.WriteByte((byte)(i >> 48));
@@ -100,7 +100,7 @@ namespace Org.BouncyCastle.Crypto.Tls
os.WriteByte((byte)i);
}
- internal static void WriteUint64(long i, byte[] buf, int offset)
+ public static void WriteUint64(long i, byte[] buf, int offset)
{
buf[offset] = (byte)(i >> 56);
buf[offset + 1] = (byte)(i >> 48);
@@ -112,29 +112,38 @@ namespace Org.BouncyCastle.Crypto.Tls
buf[offset + 7] = (byte)(i);
}
- internal static void WriteOpaque8(byte[] buf, Stream os)
+ public static void WriteOpaque8(byte[] buf, Stream os)
{
WriteUint8((byte)buf.Length, os);
os.Write(buf, 0, buf.Length);
}
- internal static void WriteOpaque16(byte[] buf, Stream os)
+ public static void WriteOpaque16(byte[] buf, Stream os)
{
WriteUint16(buf.Length, os);
os.Write(buf, 0, buf.Length);
}
- internal static void WriteOpaque24(byte[] buf, Stream os)
+ public static void WriteOpaque24(byte[] buf, Stream os)
{
WriteUint24(buf.Length, os);
os.Write(buf, 0, buf.Length);
}
- internal static void WriteUint8Array(byte[] uints, Stream os)
+ public static void WriteUint8Array(byte[] uints, Stream os)
{
os.Write(uints, 0, uints.Length);
}
+ public static void WriteUint8Array(byte[] uints, byte[] buf, int offset)
+ {
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint8(uints[i], buf, offset);
+ ++offset;
+ }
+ }
+
public static void WriteUint8ArrayWithUint8Length(byte[] uints, Stream output)
{
CheckUint8(uints.Length);
@@ -142,7 +151,14 @@ namespace Org.BouncyCastle.Crypto.Tls
WriteUint8Array(uints, output);
}
- internal static void WriteUint16Array(int[] uints, Stream os)
+ public static void WriteUint8ArrayWithUint8Length(byte[] uints, byte[] buf, int offset)
+ {
+ CheckUint8(uints.Length);
+ WriteUint8((byte)uints.Length, buf, offset);
+ WriteUint8Array(uints, buf, offset + 1);
+ }
+
+ public static void WriteUint16Array(int[] uints, Stream os)
{
for (int i = 0; i < uints.Length; ++i)
{
@@ -150,7 +166,53 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- internal static byte ReadUint8(Stream inStr)
+ public static void WriteUint16Array(int[] uints, byte[] buf, int offset)
+ {
+ for (int i = 0; i < uints.Length; ++i)
+ {
+ WriteUint16(uints[i], buf, offset);
+ offset += 2;
+ }
+ }
+
+ public static void WriteUint16ArrayWithUint16Length(int[] uints, Stream output)
+ {
+ int length = 2 * uints.Length;
+ CheckUint16(length);
+ WriteUint16(length, output);
+ WriteUint16Array(uints, output);
+ }
+
+ public static void WriteUint16ArrayWithUint16Length(int[] uints, byte[] buf, int offset)
+ {
+ int length = 2 * uints.Length;
+ CheckUint16(length);
+ WriteUint16(length, buf, offset);
+ WriteUint16Array(uints, buf, offset + 2);
+ }
+
+ public static byte[] EncodeOpaque8(byte[] buf)
+ {
+ CheckUint8(buf.Length);
+ return Arrays.Prepend(buf, (byte)buf.Length);
+ }
+
+ public static byte[] EncodeUint8ArrayWithUint8Length(byte[] uints)
+ {
+ byte[] result = new byte[1 + uints.Length];
+ WriteUint8ArrayWithUint8Length(uints, result, 0);
+ return result;
+ }
+
+ public static byte[] EncodeUint16ArrayWithUint16Length(int[] uints)
+ {
+ int length = 2 * uints.Length;
+ byte[] result = new byte[2 + length];
+ WriteUint16ArrayWithUint16Length(uints, result, 0);
+ return result;
+ }
+
+ public static byte ReadUint8(Stream inStr)
{
int i = inStr.ReadByte();
if (i < 0)
@@ -160,7 +222,7 @@ namespace Org.BouncyCastle.Crypto.Tls
return (byte)i;
}
- internal static int ReadUint16(Stream inStr)
+ public static int ReadUint16(Stream inStr)
{
int i1 = inStr.ReadByte();
int i2 = inStr.ReadByte();
@@ -171,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Tls
return i1 << 8 | i2;
}
- internal static int ReadUint24(Stream inStr)
+ public static int ReadUint24(Stream inStr)
{
int i1 = inStr.ReadByte();
int i2 = inStr.ReadByte();
@@ -193,13 +255,13 @@ namespace Org.BouncyCastle.Crypto.Tls
return buf;
}
- internal static void ReadFully(byte[] buf, Stream inStr)
+ public static void ReadFully(byte[] buf, Stream inStr)
{
if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length)
throw new EndOfStreamException();
}
- internal static byte[] ReadOpaque8(Stream inStr)
+ public static byte[] ReadOpaque8(Stream inStr)
{
byte length = ReadUint8(inStr);
byte[] bytes = new byte[length];
@@ -207,7 +269,7 @@ namespace Org.BouncyCastle.Crypto.Tls
return bytes;
}
- internal static byte[] ReadOpaque16(Stream inStr)
+ public static byte[] ReadOpaque16(Stream inStr)
{
int length = ReadUint16(inStr);
byte[] bytes = new byte[length];
@@ -221,7 +283,27 @@ namespace Org.BouncyCastle.Crypto.Tls
return ReadFully(length, input);
}
- internal static void CheckVersion(byte[] readVersion)
+ public static byte[] ReadUint8Array(int count, Stream input)
+ {
+ byte[] uints = new byte[count];
+ for (int i = 0; i < count; ++i)
+ {
+ uints[i] = ReadUint8(input);
+ }
+ return uints;
+ }
+
+ public static int[] ReadUint16Array(int count, Stream input)
+ {
+ int[] uints = new int[count];
+ for (int i = 0; i < count; ++i)
+ {
+ uints[i] = ReadUint16(input);
+ }
+ return uints;
+ }
+
+ public static void CheckVersion(byte[] readVersion)
{
if ((readVersion[0] != 3) || (readVersion[1] != 1))
{
@@ -229,7 +311,7 @@ namespace Org.BouncyCastle.Crypto.Tls
}
}
- internal static void CheckVersion(Stream inStr)
+ public static void CheckVersion(Stream inStr)
{
int i1 = inStr.ReadByte();
int i2 = inStr.ReadByte();
@@ -263,7 +345,7 @@ namespace Org.BouncyCastle.Crypto.Tls
return result;
}
- internal static void WriteGmtUnixTime(byte[] buf, int offset)
+ public static void WriteGmtUnixTime(byte[] buf, int offset)
{
int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L);
buf[offset] = (byte)(t >> 24);
@@ -272,18 +354,34 @@ namespace Org.BouncyCastle.Crypto.Tls
buf[offset + 3] = (byte)t;
}
- internal static void WriteVersion(Stream os)
+ public static void WriteVersion(Stream os)
{
os.WriteByte(3);
os.WriteByte(1);
}
- internal static void WriteVersion(byte[] buf, int offset)
+ public static void WriteVersion(byte[] buf, int offset)
{
buf[offset] = 3;
buf[offset + 1] = 1;
}
+ public static byte[] GetExtensionData(Hashtable extensions, int extensionType)
+ {
+ return extensions == null ? null : (byte[])extensions[extensionType];
+ }
+
+ public static bool HasExpectedEmptyExtensionData(Hashtable extensions, int extensionType,
+ byte alertDescription)
+ {
+ byte[] extension_data = GetExtensionData(extensions, extensionType);
+ if (extension_data == null)
+ return false;
+ if (extension_data.Length != 0)
+ throw new TlsFatalAlert(alertDescription);
+ return true;
+ }
+
public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
Stream output)
{
diff --git a/crypto/src/crypto/tls/UserMappingType.cs b/crypto/src/crypto/tls/UserMappingType.cs
index 6e6d40a58..6cff51736 100644
--- a/crypto/src/crypto/tls/UserMappingType.cs
+++ b/crypto/src/crypto/tls/UserMappingType.cs
@@ -8,6 +8,6 @@ namespace Org.BouncyCastle.Crypto.Tls
/*
* RFC 4681
*/
- public const short upn_domain_hint = 64;
+ public const byte upn_domain_hint = 64;
}
}
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 37da3940f..e629fcf65 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -366,6 +366,36 @@ namespace Org.BouncyCastle.Utilities
return existing;
}
+ public static bool Contains(byte[] a, byte n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static bool Contains(short[] a, short n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
+ public static bool Contains(int[] a, int n)
+ {
+ for (int i = 0; i < a.Length; ++i)
+ {
+ if (a[i] == n)
+ return true;
+ }
+ return false;
+ }
+
public static void Fill(
byte[] buf,
byte b)
@@ -384,6 +414,42 @@ namespace Org.BouncyCastle.Utilities
return result;
}
+ public static byte[] Append(byte[] a, byte b)
+ {
+ if (a == null)
+ return new byte[] { b };
+
+ int length = a.Length;
+ byte[] result = new byte[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static short[] Append(short[] a, short b)
+ {
+ if (a == null)
+ return new short[] { b };
+
+ int length = a.Length;
+ short[] result = new short[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
+ public static int[] Append(int[] a, int b)
+ {
+ if (a == null)
+ return new int[] { b };
+
+ int length = a.Length;
+ int[] result = new int[length + 1];
+ Array.Copy(a, 0, result, 0, length);
+ result[length] = b;
+ return result;
+ }
+
public static byte[] Concatenate(byte[] a, byte[] b)
{
if (a == null)
@@ -397,6 +463,42 @@ namespace Org.BouncyCastle.Utilities
return rv;
}
+ public static byte[] Prepend(byte[] a, byte b)
+ {
+ if (a == null)
+ return new byte[] { b };
+
+ int length = a.Length;
+ byte[] result = new byte[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static short[] Prepend(short[] a, short b)
+ {
+ if (a == null)
+ return new short[] { b };
+
+ int length = a.Length;
+ short[] result = new short[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
+ public static int[] Prepend(int[] a, int b)
+ {
+ if (a == null)
+ return new int[] { b };
+
+ int length = a.Length;
+ int[] result = new int[length + 1];
+ Array.Copy(a, 0, result, 1, length);
+ result[0] = b;
+ return result;
+ }
+
public static byte[] Reverse(byte[] a)
{
if (a == null)
|