You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
438 lines
10 KiB
438 lines
10 KiB
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) |
|
#pragma warning disable |
|
using System; |
|
using System.Collections; |
|
|
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Security.Certificates; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; |
|
using BestHTTP.SecureProtocol.Org.BouncyCastle.X509.Store; |
|
|
|
namespace BestHTTP.SecureProtocol.Org.BouncyCastle.X509 |
|
{ |
|
/// <remarks> |
|
/// The Holder object. |
|
/// <pre> |
|
/// Holder ::= SEQUENCE { |
|
/// baseCertificateID [0] IssuerSerial OPTIONAL, |
|
/// -- the issuer and serial number of |
|
/// -- the holder's Public Key Certificate |
|
/// entityName [1] GeneralNames OPTIONAL, |
|
/// -- the name of the claimant or role |
|
/// objectDigestInfo [2] ObjectDigestInfo OPTIONAL |
|
/// -- used to directly authenticate the holder, |
|
/// -- for example, an executable |
|
/// } |
|
/// </pre> |
|
/// </remarks> |
|
public class AttributeCertificateHolder |
|
//: CertSelector, Selector |
|
: IX509Selector |
|
{ |
|
internal readonly Holder holder; |
|
|
|
internal AttributeCertificateHolder( |
|
Asn1Sequence seq) |
|
{ |
|
holder = Holder.GetInstance(seq); |
|
} |
|
|
|
public AttributeCertificateHolder( |
|
X509Name issuerName, |
|
BigInteger serialNumber) |
|
{ |
|
holder = new Holder( |
|
new IssuerSerial( |
|
GenerateGeneralNames(issuerName), |
|
new DerInteger(serialNumber))); |
|
} |
|
|
|
public AttributeCertificateHolder( |
|
X509Certificate cert) |
|
{ |
|
X509Name name; |
|
try |
|
{ |
|
name = PrincipalUtilities.GetIssuerX509Principal(cert); |
|
} |
|
catch (Exception e) |
|
{ |
|
throw new CertificateParsingException(e.Message); |
|
} |
|
|
|
holder = new Holder(new IssuerSerial(GenerateGeneralNames(name), new DerInteger(cert.SerialNumber))); |
|
} |
|
|
|
public AttributeCertificateHolder( |
|
X509Name principal) |
|
{ |
|
holder = new Holder(GenerateGeneralNames(principal)); |
|
} |
|
|
|
/** |
|
* Constructs a holder for v2 attribute certificates with a hash value for |
|
* some type of object. |
|
* <p> |
|
* <code>digestedObjectType</code> can be one of the following: |
|
* <ul> |
|
* <li>0 - publicKey - A hash of the public key of the holder must be |
|
* passed.</li> |
|
* <li>1 - publicKeyCert - A hash of the public key certificate of the |
|
* holder must be passed.</li> |
|
* <li>2 - otherObjectDigest - A hash of some other object type must be |
|
* passed. <code>otherObjectTypeID</code> must not be empty.</li> |
|
* </ul> |
|
* </p> |
|
* <p>This cannot be used if a v1 attribute certificate is used.</p> |
|
* |
|
* @param digestedObjectType The digest object type. |
|
* @param digestAlgorithm The algorithm identifier for the hash. |
|
* @param otherObjectTypeID The object type ID if |
|
* <code>digestedObjectType</code> is |
|
* <code>otherObjectDigest</code>. |
|
* @param objectDigest The hash value. |
|
*/ |
|
public AttributeCertificateHolder( |
|
int digestedObjectType, |
|
string digestAlgorithm, |
|
string otherObjectTypeID, |
|
byte[] objectDigest) |
|
{ |
|
// TODO Allow 'objectDigest' to be null? |
|
|
|
holder = new Holder(new ObjectDigestInfo(digestedObjectType, otherObjectTypeID, |
|
new AlgorithmIdentifier(new DerObjectIdentifier(digestAlgorithm)), Arrays.Clone(objectDigest))); |
|
} |
|
|
|
/** |
|
* Returns the digest object type if an object digest info is used. |
|
* <p> |
|
* <ul> |
|
* <li>0 - publicKey - A hash of the public key of the holder must be |
|
* passed.</li> |
|
* <li>1 - publicKeyCert - A hash of the public key certificate of the |
|
* holder must be passed.</li> |
|
* <li>2 - otherObjectDigest - A hash of some other object type must be |
|
* passed. <code>otherObjectTypeID</code> must not be empty.</li> |
|
* </ul> |
|
* </p> |
|
* |
|
* @return The digest object type or -1 if no object digest info is set. |
|
*/ |
|
public int DigestedObjectType |
|
{ |
|
get |
|
{ |
|
ObjectDigestInfo odi = holder.ObjectDigestInfo; |
|
|
|
return odi == null |
|
? -1 |
|
: odi.DigestedObjectType.IntValueExact; |
|
} |
|
} |
|
|
|
/** |
|
* Returns the other object type ID if an object digest info is used. |
|
* |
|
* @return The other object type ID or <code>null</code> if no object |
|
* digest info is set. |
|
*/ |
|
public string DigestAlgorithm |
|
{ |
|
get |
|
{ |
|
ObjectDigestInfo odi = holder.ObjectDigestInfo; |
|
|
|
return odi == null |
|
? null |
|
: odi.DigestAlgorithm.Algorithm.Id; |
|
} |
|
} |
|
|
|
/** |
|
* Returns the hash if an object digest info is used. |
|
* |
|
* @return The hash or <code>null</code> if no object digest info is set. |
|
*/ |
|
public byte[] GetObjectDigest() |
|
{ |
|
ObjectDigestInfo odi = holder.ObjectDigestInfo; |
|
|
|
return odi == null |
|
? null |
|
: odi.ObjectDigest.GetBytes(); |
|
} |
|
|
|
/** |
|
* Returns the digest algorithm ID if an object digest info is used. |
|
* |
|
* @return The digest algorithm ID or <code>null</code> if no object |
|
* digest info is set. |
|
*/ |
|
public string OtherObjectTypeID |
|
{ |
|
get |
|
{ |
|
ObjectDigestInfo odi = holder.ObjectDigestInfo; |
|
|
|
return odi == null |
|
? null |
|
: odi.OtherObjectTypeID.Id; |
|
} |
|
} |
|
|
|
private GeneralNames GenerateGeneralNames( |
|
X509Name principal) |
|
{ |
|
// return GeneralNames.GetInstance(new DerSequence(new GeneralName(principal))); |
|
return new GeneralNames(new GeneralName(principal)); |
|
} |
|
|
|
private bool MatchesDN( |
|
X509Name subject, |
|
GeneralNames targets) |
|
{ |
|
GeneralName[] names = targets.GetNames(); |
|
|
|
for (int i = 0; i != names.Length; i++) |
|
{ |
|
GeneralName gn = names[i]; |
|
|
|
if (gn.TagNo == GeneralName.DirectoryName) |
|
{ |
|
try |
|
{ |
|
if (X509Name.GetInstance(gn.Name).Equivalent(subject)) |
|
{ |
|
return true; |
|
} |
|
} |
|
catch (Exception) |
|
{ |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
private object[] GetNames( |
|
GeneralName[] names) |
|
{ |
|
int count = 0; |
|
for (int i = 0; i != names.Length; i++) |
|
{ |
|
if (names[i].TagNo == GeneralName.DirectoryName) |
|
{ |
|
++count; |
|
} |
|
} |
|
|
|
object[] result = new object[count]; |
|
|
|
int pos = 0; |
|
for (int i = 0; i != names.Length; i++) |
|
{ |
|
if (names[i].TagNo == GeneralName.DirectoryName) |
|
{ |
|
result[pos++] = X509Name.GetInstance(names[i].Name); |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
private X509Name[] GetPrincipals( |
|
GeneralNames names) |
|
{ |
|
object[] p = this.GetNames(names.GetNames()); |
|
|
|
int count = 0; |
|
|
|
for (int i = 0; i != p.Length; i++) |
|
{ |
|
if (p[i] is X509Name) |
|
{ |
|
++count; |
|
} |
|
} |
|
|
|
X509Name[] result = new X509Name[count]; |
|
|
|
int pos = 0; |
|
for (int i = 0; i != p.Length; i++) |
|
{ |
|
if (p[i] is X509Name) |
|
{ |
|
result[pos++] = (X509Name)p[i]; |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
/** |
|
* Return any principal objects inside the attribute certificate holder entity names field. |
|
* |
|
* @return an array of IPrincipal objects (usually X509Name), null if no entity names field is set. |
|
*/ |
|
public X509Name[] GetEntityNames() |
|
{ |
|
if (holder.EntityName != null) |
|
{ |
|
return GetPrincipals(holder.EntityName); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
/** |
|
* Return the principals associated with the issuer attached to this holder |
|
* |
|
* @return an array of principals, null if no BaseCertificateID is set. |
|
*/ |
|
public X509Name[] GetIssuer() |
|
{ |
|
if (holder.BaseCertificateID != null) |
|
{ |
|
return GetPrincipals(holder.BaseCertificateID.Issuer); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
/** |
|
* Return the serial number associated with the issuer attached to this holder. |
|
* |
|
* @return the certificate serial number, null if no BaseCertificateID is set. |
|
*/ |
|
public BigInteger SerialNumber |
|
{ |
|
get |
|
{ |
|
if (holder.BaseCertificateID != null) |
|
{ |
|
return holder.BaseCertificateID.Serial.Value; |
|
} |
|
|
|
return null; |
|
} |
|
} |
|
|
|
public object Clone() |
|
{ |
|
return new AttributeCertificateHolder((Asn1Sequence)holder.ToAsn1Object()); |
|
} |
|
|
|
public bool Match( |
|
X509Certificate x509Cert) |
|
{ |
|
try |
|
{ |
|
if (holder.BaseCertificateID != null) |
|
{ |
|
return holder.BaseCertificateID.Serial.HasValue(x509Cert.SerialNumber) |
|
&& MatchesDN(PrincipalUtilities.GetIssuerX509Principal(x509Cert), holder.BaseCertificateID.Issuer); |
|
} |
|
|
|
if (holder.EntityName != null) |
|
{ |
|
if (MatchesDN(PrincipalUtilities.GetSubjectX509Principal(x509Cert), holder.EntityName)) |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
if (holder.ObjectDigestInfo != null) |
|
{ |
|
IDigest md = null; |
|
try |
|
{ |
|
md = DigestUtilities.GetDigest(DigestAlgorithm); |
|
} |
|
catch (Exception) |
|
{ |
|
return false; |
|
} |
|
|
|
switch (DigestedObjectType) |
|
{ |
|
case ObjectDigestInfo.PublicKey: |
|
{ |
|
// TODO: DSA Dss-parms |
|
|
|
//byte[] b = x509Cert.GetPublicKey().getEncoded(); |
|
// TODO Is this the right way to encode? |
|
byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo( |
|
x509Cert.GetPublicKey()).GetEncoded(); |
|
md.BlockUpdate(b, 0, b.Length); |
|
break; |
|
} |
|
|
|
case ObjectDigestInfo.PublicKeyCert: |
|
{ |
|
byte[] b = x509Cert.GetEncoded(); |
|
md.BlockUpdate(b, 0, b.Length); |
|
break; |
|
} |
|
|
|
// TODO Default handler? |
|
} |
|
|
|
// TODO Shouldn't this be the other way around? |
|
if (!Arrays.AreEqual(DigestUtilities.DoFinal(md), GetObjectDigest())) |
|
{ |
|
return false; |
|
} |
|
} |
|
} |
|
catch (CertificateEncodingException) |
|
{ |
|
return false; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
public override bool Equals( |
|
object obj) |
|
{ |
|
if (obj == this) |
|
{ |
|
return true; |
|
} |
|
|
|
if (!(obj is AttributeCertificateHolder)) |
|
{ |
|
return false; |
|
} |
|
|
|
AttributeCertificateHolder other = (AttributeCertificateHolder)obj; |
|
|
|
return this.holder.Equals(other.holder); |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
return this.holder.GetHashCode(); |
|
} |
|
|
|
public bool Match( |
|
object obj) |
|
{ |
|
if (!(obj is X509Certificate)) |
|
{ |
|
return false; |
|
} |
|
|
|
// return Match((Certificate)obj); |
|
return Match((X509Certificate)obj); |
|
} |
|
} |
|
} |
|
#pragma warning restore |
|
#endif
|
|
|