#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) #pragma warning disable using System; using System.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; using BestHTTP.SecureProtocol.Org.BouncyCastle.Security; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto.Impl.BC { /// Implementation class for a single X.509 certificate based on the BC light-weight API. public class BcTlsCertificate : TlsCertificate { /// public static BcTlsCertificate Convert(BcTlsCrypto crypto, TlsCertificate certificate) { if (certificate is BcTlsCertificate) return (BcTlsCertificate)certificate; return new BcTlsCertificate(crypto, certificate.GetEncoded()); } /// public static X509CertificateStructure ParseCertificate(byte[] encoding) { try { return X509CertificateStructure.GetInstance(encoding); } catch (Exception e) { throw new TlsFatalAlert(AlertDescription.bad_certificate, e); } } protected readonly BcTlsCrypto m_crypto; protected readonly X509CertificateStructure m_certificate; protected DHPublicKeyParameters m_pubKeyDH = null; protected ECPublicKeyParameters m_pubKeyEC = null; protected Ed25519PublicKeyParameters m_pubKeyEd25519 = null; protected Ed448PublicKeyParameters m_pubKeyEd448 = null; protected RsaKeyParameters m_pubKeyRsa = null; /// public BcTlsCertificate(BcTlsCrypto crypto, byte[] encoding) : this(crypto, ParseCertificate(encoding)) { } public BcTlsCertificate(BcTlsCrypto crypto, X509CertificateStructure certificate) { this.m_crypto = crypto; this.m_certificate = certificate; } /// public virtual TlsEncryptor CreateEncryptor(int tlsCertificateRole) { ValidateKeyUsage(KeyUsage.KeyEncipherment); switch (tlsCertificateRole) { case TlsCertificateRole.RsaEncryption: { this.m_pubKeyRsa = GetPubKeyRsa(); return new BcTlsRsaEncryptor(m_crypto, m_pubKeyRsa); } // TODO[gmssl] //case TlsCertificateRole.Sm2Encryption: //{ // this.m_pubKeyEC = GetPubKeyEC(); // return new BcTlsSM2Encryptor(m_crypto, m_pubKeyEC); //} } throw new TlsFatalAlert(AlertDescription.certificate_unknown); } /// public virtual TlsVerifier CreateVerifier(short signatureAlgorithm) { switch (signatureAlgorithm) { case SignatureAlgorithm.rsa_pss_rsae_sha256: case SignatureAlgorithm.rsa_pss_rsae_sha384: case SignatureAlgorithm.rsa_pss_rsae_sha512: case SignatureAlgorithm.ed25519: case SignatureAlgorithm.ed448: case SignatureAlgorithm.rsa_pss_pss_sha256: case SignatureAlgorithm.rsa_pss_pss_sha384: case SignatureAlgorithm.rsa_pss_pss_sha512: return CreateVerifier(SignatureScheme.From(HashAlgorithm.Intrinsic, signatureAlgorithm)); } ValidateKeyUsage(KeyUsage.DigitalSignature); switch (signatureAlgorithm) { case SignatureAlgorithm.rsa: ValidateRsa_Pkcs1(); return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); case SignatureAlgorithm.dsa: return new BcTlsDsaVerifier(m_crypto, GetPubKeyDss()); case SignatureAlgorithm.ecdsa: return new BcTlsECDsaVerifier(m_crypto, GetPubKeyEC()); default: throw new TlsFatalAlert(AlertDescription.certificate_unknown); } } /// public virtual TlsVerifier 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: return new BcTlsECDsa13Verifier(m_crypto, GetPubKeyEC(), signatureScheme); case SignatureScheme.ed25519: return new BcTlsEd25519Verifier(m_crypto, GetPubKeyEd25519()); case SignatureScheme.ed448: return new BcTlsEd448Verifier(m_crypto, GetPubKeyEd448()); case SignatureScheme.rsa_pkcs1_sha1: case SignatureScheme.rsa_pkcs1_sha256: case SignatureScheme.rsa_pkcs1_sha384: case SignatureScheme.rsa_pkcs1_sha512: { ValidateRsa_Pkcs1(); return new BcTlsRsaVerifier(m_crypto, GetPubKeyRsa()); } case SignatureScheme.rsa_pss_pss_sha256: case SignatureScheme.rsa_pss_pss_sha384: case SignatureScheme.rsa_pss_pss_sha512: { ValidateRsa_Pss_Pss(SignatureScheme.GetSignatureAlgorithm(signatureScheme)); return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); } case SignatureScheme.rsa_pss_rsae_sha256: case SignatureScheme.rsa_pss_rsae_sha384: case SignatureScheme.rsa_pss_rsae_sha512: { ValidateRsa_Pss_Rsae(); return new BcTlsRsaPssVerifier(m_crypto, GetPubKeyRsa(), signatureScheme); } // TODO[RFC 8998] //case SignatureScheme.sm2sig_sm3: // return new BcTlsSM2Verifier(m_crypto, GetPubKeyEC(), Strings.ToByteArray("TLSv1.3+GM+Cipher+Suite")); default: throw new TlsFatalAlert(AlertDescription.certificate_unknown); } } /// public virtual byte[] GetEncoded() { return m_certificate.GetEncoded(Asn1Encodable.Der); } /// public virtual byte[] GetExtension(DerObjectIdentifier extensionOid) { X509Extensions extensions = m_certificate.TbsCertificate.Extensions; if (extensions != null) { X509Extension extension = extensions.GetExtension(extensionOid); if (extension != null) { return Arrays.Clone(extension.Value.GetOctets()); } } return null; } public virtual BigInteger SerialNumber { get { return m_certificate.SerialNumber.Value; } } public virtual string SigAlgOid { get { return m_certificate.SignatureAlgorithm.Algorithm.Id; } } public virtual Asn1Encodable GetSigAlgParams() { return m_certificate.SignatureAlgorithm.Parameters; } /// public virtual short GetLegacySignatureAlgorithm() { AsymmetricKeyParameter publicKey = GetPublicKey(); if (publicKey.IsPrivate) throw new TlsFatalAlert(AlertDescription.internal_error); if (!SupportsKeyUsage(KeyUsage.DigitalSignature)) return -1; /* * RFC 5246 7.4.6. Client Certificate */ /* * RSA public key; the certificate MUST allow the key to be used for signing with the * signature scheme and hash algorithm that will be employed in the certificate verify * message. */ if (publicKey is RsaKeyParameters) return SignatureAlgorithm.rsa; /* * DSA public key; the certificate MUST allow the key to be used for signing with the * hash algorithm that will be employed in the certificate verify message. */ if (publicKey is DsaPublicKeyParameters) return SignatureAlgorithm.dsa; /* * ECDSA-capable public key; the certificate MUST allow the key to be used for signing * with the hash algorithm that will be employed in the certificate verify message; the * public key MUST use a curve and point format supported by the server. */ if (publicKey is ECPublicKeyParameters) { // TODO Check the curve and point format return SignatureAlgorithm.ecdsa; } return -1; } /// public virtual DHPublicKeyParameters GetPubKeyDH() { try { return (DHPublicKeyParameters)GetPublicKey(); } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } } /// public virtual DsaPublicKeyParameters GetPubKeyDss() { try { return (DsaPublicKeyParameters)GetPublicKey(); } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } } /// public virtual ECPublicKeyParameters GetPubKeyEC() { try { return (ECPublicKeyParameters)GetPublicKey(); } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } } /// public virtual Ed25519PublicKeyParameters GetPubKeyEd25519() { try { return (Ed25519PublicKeyParameters)GetPublicKey(); } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } } /// public virtual Ed448PublicKeyParameters GetPubKeyEd448() { try { return (Ed448PublicKeyParameters)GetPublicKey(); } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } } /// public virtual RsaKeyParameters GetPubKeyRsa() { try { return (RsaKeyParameters)GetPublicKey(); } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } } /// public virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm) { return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.DigitalSignature); } /// public virtual bool SupportsSignatureAlgorithmCA(short signatureAlgorithm) { return SupportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.KeyCertSign); } /// public virtual TlsCertificate CheckUsageInRole(int tlsCertificateRole) { switch (tlsCertificateRole) { case TlsCertificateRole.DH: { ValidateKeyUsage(KeyUsage.KeyAgreement); this.m_pubKeyDH = GetPubKeyDH(); return this; } case TlsCertificateRole.ECDH: { ValidateKeyUsage(KeyUsage.KeyAgreement); this.m_pubKeyEC = GetPubKeyEC(); return this; } } throw new TlsFatalAlert(AlertDescription.certificate_unknown); } /// protected virtual AsymmetricKeyParameter GetPublicKey() { 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) { X509Extensions exts = m_certificate.TbsCertificate.Extensions; if (exts != null) { KeyUsage ku = KeyUsage.FromExtensions(exts); if (ku != null) { int bits = ku.GetBytes()[0] & 0xff; if ((bits & keyUsageBits) != keyUsageBits) return false; } } return true; } protected virtual bool SupportsRsa_Pkcs1() { AlgorithmIdentifier pubKeyAlgID = m_certificate.SubjectPublicKeyInfo.AlgorithmID; return RsaUtilities.SupportsPkcs1(pubKeyAlgID); } protected virtual bool SupportsRsa_Pss_Pss(short signatureAlgorithm) { AlgorithmIdentifier pubKeyAlgID = m_certificate.SubjectPublicKeyInfo.AlgorithmID; return RsaUtilities.SupportsPss_Pss(signatureAlgorithm, pubKeyAlgID); } protected virtual bool SupportsRsa_Pss_Rsae() { AlgorithmIdentifier pubKeyAlgID = m_certificate.SubjectPublicKeyInfo.AlgorithmID; return RsaUtilities.SupportsPss_Rsae(pubKeyAlgID); } /// protected virtual bool SupportsSignatureAlgorithm(short signatureAlgorithm, int keyUsage) { if (!SupportsKeyUsage(keyUsage)) return false; AsymmetricKeyParameter publicKey = GetPublicKey(); switch (signatureAlgorithm) { case SignatureAlgorithm.rsa: return SupportsRsa_Pkcs1() && publicKey is RsaKeyParameters; case SignatureAlgorithm.dsa: return publicKey is DsaPublicKeyParameters; case SignatureAlgorithm.ecdsa: case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: return publicKey is ECPublicKeyParameters; case SignatureAlgorithm.ed25519: return publicKey is Ed25519PublicKeyParameters; case SignatureAlgorithm.ed448: return publicKey is Ed448PublicKeyParameters; case SignatureAlgorithm.rsa_pss_rsae_sha256: case SignatureAlgorithm.rsa_pss_rsae_sha384: case SignatureAlgorithm.rsa_pss_rsae_sha512: return SupportsRsa_Pss_Rsae() && publicKey is RsaKeyParameters; case SignatureAlgorithm.rsa_pss_pss_sha256: case SignatureAlgorithm.rsa_pss_pss_sha384: case SignatureAlgorithm.rsa_pss_pss_sha512: return SupportsRsa_Pss_Pss(signatureAlgorithm) && publicKey is RsaKeyParameters; default: return false; } } /// public virtual void ValidateKeyUsage(int keyUsageBits) { if (!SupportsKeyUsage(keyUsageBits)) throw new TlsFatalAlert(AlertDescription.certificate_unknown); } /// protected virtual void ValidateRsa_Pkcs1() { if (!SupportsRsa_Pkcs1()) throw new TlsFatalAlert(AlertDescription.certificate_unknown); } /// protected virtual void ValidateRsa_Pss_Pss(short signatureAlgorithm) { if (!SupportsRsa_Pss_Pss(signatureAlgorithm)) throw new TlsFatalAlert(AlertDescription.certificate_unknown); } /// protected virtual void ValidateRsa_Pss_Rsae() { if (!SupportsRsa_Pss_Rsae()) throw new TlsFatalAlert(AlertDescription.certificate_unknown); } } } #pragma warning restore #endif