All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.vt.middleware.crypt.x509.ExtensionFactory Maven / Gradle / Ivy

There is a newer version: 2.2
Show newest version
/*
  $Id$

  Copyright (C) 2007-2011 Virginia Tech.
  All rights reserved.

  SEE LICENSE FOR MORE INFORMATION

  Author:  Middleware Services
  Email:   [email protected]
  Version: $Revision$
  Updated: $Date$
*/
package edu.vt.middleware.crypt.x509;

import java.util.ArrayList;
import java.util.List;
import edu.vt.middleware.crypt.x509.types.AccessDescription;
import edu.vt.middleware.crypt.x509.types.AccessDescriptionList;
import edu.vt.middleware.crypt.x509.types.AccessMethod;
import edu.vt.middleware.crypt.x509.types.AuthorityKeyIdentifier;
import edu.vt.middleware.crypt.x509.types.BasicConstraints;
import edu.vt.middleware.crypt.x509.types.DistributionPoint;
import edu.vt.middleware.crypt.x509.types.DistributionPointList;
import edu.vt.middleware.crypt.x509.types.GeneralName;
import edu.vt.middleware.crypt.x509.types.GeneralNameList;
import edu.vt.middleware.crypt.x509.types.GeneralNameType;
import edu.vt.middleware.crypt.x509.types.KeyIdentifier;
import edu.vt.middleware.crypt.x509.types.KeyPurposeId;
import edu.vt.middleware.crypt.x509.types.KeyPurposeIdList;
import edu.vt.middleware.crypt.x509.types.KeyUsage;
import edu.vt.middleware.crypt.x509.types.NoticeReference;
import edu.vt.middleware.crypt.x509.types.PolicyInformation;
import edu.vt.middleware.crypt.x509.types.PolicyInformationList;
import edu.vt.middleware.crypt.x509.types.PolicyQualifierInfo;
import edu.vt.middleware.crypt.x509.types.ReasonFlags;
import edu.vt.middleware.crypt.x509.types.UserNotice;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DEREncodable;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERInteger;

/**
 * Creates X.509v3 extension types in the VT Crypt namespace from BouncyCastle
 * ASN1Encodable types.
 *
 * @author  Middleware Services
 * @version  $Revision: 428 $
 */
public final class ExtensionFactory
{

  /** Private default constructor for utility class. */
  private ExtensionFactory() {}


  /**
   * Creates an instance of a VT Crypt X.509v3 extension type from the
   * corresponding Bouncy Castle extension type.
   *
   * @param  type  Type of extension.
   * @param  encodedExtension  DER encoded data representing the extension field
   * data.
   *
   * @return  An extension type from the 
   * edu.vt.middleware.crypt.x509.types package that is semantically
   * equivalent to the given Bouncy Castle object.
   *
   * @throws  IllegalArgumentException  If given ASN.1 encodable object is not
   * compatible with the given extension type.
   */
  public static Object createInstance(
    final DEREncodable encodedExtension,
    final ExtensionType type)
  {
    Object extension = null;
    try {
      switch (type) {

      case AuthorityInformationAccess:
        extension = createAccessDescriptionList(encodedExtension);
        break;

      case AuthorityKeyIdentifier:
        extension = createAuthorityKeyIdentifier(encodedExtension);
        break;

      case BasicConstraints:
        extension = createBasicConstraints(encodedExtension);
        break;

      case CertificatePolicies:
        extension = createPolicyInformationList(encodedExtension);
        break;

      case CRLDistributionPoints:
        extension = createDistributionPointList(encodedExtension);
        break;

      case ExtendedKeyUsage:
        extension = createKeyPurposeIdList(encodedExtension);
        break;

      case IssuerAlternativeName:
      case SubjectAlternativeName:
        extension = createGeneralNameList(encodedExtension);
        break;

      case KeyUsage:
        extension = createKeyUsage(encodedExtension);
        break;

      case NameConstraints:
        break;

      case PolicyConstraints:
        break;

      case PolicyMappings:
        break;

      case PrivateKeyUsagePeriod:
        break;

      case SubjectDirectoryAttributes:
        break;

      case SubjectKeyIdentifier:
        extension = createKeyIdentifier(encodedExtension);
        break;

      default:
        throw new UnsupportedOperationException(type + " not yet supported.");
      }
    } catch (Exception e) {
      throw new IllegalArgumentException(
        String.format(
          "Cannot create %s from %s",
          type,
          encodedExtension.getClass().getSimpleName()),
        e);
    }
    return extension;
  }


  /**
   * Creates a {@link GeneralNameList} object from DER data.
   *
   * @param  enc  DER encoded general names data.
   *
   * @return  Collection of general names.
   */
  public static GeneralNameList createGeneralNameList(final DEREncodable enc)
  {
    final List nameList = new ArrayList();
    for (
      org.bouncycastle.asn1.x509.GeneralName name :
        org.bouncycastle.asn1.x509.GeneralNames.getInstance(enc).getNames()) {
      nameList.add(createGeneralName(name));
    }
    return new GeneralNameList(nameList);
  }


  /**
   * Creates a {@link GeneralName} object from DER data.
   *
   * @param  enc  DER encoded general names data.
   *
   * @return  General name.
   */
  public static GeneralName createGeneralName(final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.GeneralName name =
      org.bouncycastle.asn1.x509.GeneralName.getInstance(enc);
    return
      new GeneralName(
        name.getName().toString(),
        GeneralNameType.fromTagNumber(name.getTagNo()));
  }


  /**
   * Creates a {@link BasicConstraints} object from DER data.
   *
   * @param  enc  DER encoded basic constraints data.
   *
   * @return  Basic constraints.
   */
  public static BasicConstraints createBasicConstraints(final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.BasicConstraints constraints =
      org.bouncycastle.asn1.x509.BasicConstraints.getInstance(enc);
    if (constraints.getPathLenConstraint() != null) {
      return
        new BasicConstraints(
          constraints.isCA(),
          constraints.getPathLenConstraint().intValue());
    } else {
      return new BasicConstraints(constraints.isCA());
    }
  }


  /**
   * Creates a {@link PolicyInformationList} object from DER data.
   *
   * @param  enc  DER encoded policy information data; must be 
   * ASN1Sequence.
   *
   * @return  Certificate policy information listing.
   */
  public static PolicyInformationList createPolicyInformationList(
    final DEREncodable enc)
  {
    if (!(enc instanceof ASN1Sequence)) {
      throw new IllegalArgumentException(
        "Expected ASN1Sequence but got " + enc);
    }

    final ASN1Sequence seq = (ASN1Sequence) enc;
    final List policies = new ArrayList(
      seq.size());
    for (int i = 0; i < seq.size(); i++) {
      policies.add(createPolicyInformation(seq.getObjectAt(i)));
    }
    return
      new PolicyInformationList(
        policies.toArray(new PolicyInformation[policies.size()]));
  }


  /**
   * Creates a {@link PolicyInformation} object from DER data.
   *
   * @param  enc  DER encoded policy information data.
   *
   * @return  Certificate policy information object.
   */
  public static PolicyInformation createPolicyInformation(
    final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.PolicyInformation info =
      org.bouncycastle.asn1.x509.PolicyInformation.getInstance(enc);
    final ASN1Sequence encodedQualifiers = info.getPolicyQualifiers();
    if (encodedQualifiers != null) {
      final int size = encodedQualifiers.size();
      final List qualifiers =
        new ArrayList(size);
      for (int i = 0; i < size; i++) {
        final DEREncodable item = encodedQualifiers.getObjectAt(i);
        qualifiers.add(createPolicyQualifierInfo(item));
      }
      return
        new PolicyInformation(
          info.getPolicyIdentifier().toString(),
          qualifiers.toArray(new PolicyQualifierInfo[size]));
    } else {
      return new PolicyInformation(info.getPolicyIdentifier().toString());
    }
  }


  /**
   * Creates a {@link PolicyQualifierInfo} object from DER data.
   *
   * @param  enc  DER encoded policy information data.
   *
   * @return  Certificate policy qualifier.
   */
  public static PolicyQualifierInfo createPolicyQualifierInfo(
    final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.PolicyQualifierInfo policyQualifier =
      org.bouncycastle.asn1.x509.PolicyQualifierInfo.getInstance(enc);
    final DEREncodable qualifier = policyQualifier.getQualifier();
    if (qualifier instanceof DERIA5String) {
      return new PolicyQualifierInfo(qualifier.toString());
    } else {
      return new PolicyQualifierInfo(createUserNotice(qualifier));
    }
  }


  /**
   * Creates a {@link UserNotice} object from DER data.
   *
   * @param  enc  DER encoded user notice; must be ASN1Sequence.
   *
   * @return  User notice.
   */
  public static UserNotice createUserNotice(final DEREncodable enc)
  {
    if (!(enc instanceof ASN1Sequence)) {
      throw new IllegalArgumentException(
        "Expected ASN1Sequence but got " + enc);
    }

    final ASN1Sequence seq = (ASN1Sequence) enc;
    UserNotice result = null;
    if (seq.size() == 0) {
      // Bouncy Castle will throw an exception if sequence size is 0
      // which is reasonable, since an empty user notice is nonsense.
      // However this is not strictly conformant to RFC 2459 section 4.2.1.5
      // where both UserNotice fields are optional, which would allow
      // for an empty notice.
      // We allow an empty UserNotice to be more strictly conformant.
      result = new UserNotice();
    } else {
      final org.bouncycastle.asn1.x509.UserNotice notice =
        new org.bouncycastle.asn1.x509.UserNotice(seq);
      if (notice.getExplicitText() != null) {
        if (notice.getNoticeRef() != null) {
          result = new UserNotice(
            createNoticeReference(notice.getNoticeRef()),
            notice.getExplicitText().getString());
        } else {
          result = new UserNotice(notice.getExplicitText().getString());
        }
      } else {
        // UserNotice must contain NoticeReference since
        // there is no explicitText yet seq has non-zero size
        result = new UserNotice(createNoticeReference(notice.getNoticeRef()));
      }
    }
    return result;
  }


  /**
   * Creates a {@link NoticeReference} object from DER data.
   *
   * @param  enc  DER encoded user notice; must be either 
   * ASN1Sequence or 
   * org.bouncycastle.asn1.x509.NoticeReference object.
   *
   * @return  Notice reference.
   */
  public static NoticeReference createNoticeReference(final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.NoticeReference notRef =
      org.bouncycastle.asn1.x509.NoticeReference.getInstance(enc);
    // Build the array of notice numbers
    final int[] notNums = new int[notRef.getNoticeNumbers().size()];
    for (int i = 0; i < notNums.length; i++) {
      final DERInteger num = (DERInteger) notRef.getNoticeNumbers().getObjectAt(
        i);
      notNums[i] = num.getValue().intValue();
    }
    return new NoticeReference(notRef.getOrganization().toString(), notNums);
  }


  /**
   * Creates a {@link KeyIdentifier} object from DER data.
   *
   * @param  enc  DER encoded policy information data; must be 
   * ASN1OctetString.
   *
   * @return  Key identifier.
   */
  public static KeyIdentifier createKeyIdentifier(final DEREncodable enc)
  {
    if (!(enc instanceof ASN1OctetString)) {
      throw new IllegalArgumentException(
        "Expected ASN1OctetString but got " + enc);
    }

    final ASN1OctetString os = (ASN1OctetString) enc;
    return new KeyIdentifier(os.getOctets());
  }


  /**
   * Creates a {@link AuthorityKeyIdentifier} object from DER data.
   *
   * @param  enc  DER encoded authority key identifier data.
   *
   * @return  Authority key identifier.
   */
  public static AuthorityKeyIdentifier createAuthorityKeyIdentifier(
    final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.AuthorityKeyIdentifier aki =
      org.bouncycastle.asn1.x509.AuthorityKeyIdentifier.getInstance(enc);
    KeyIdentifier keyIdentifier = null;
    if (aki.getKeyIdentifier() != null) {
      keyIdentifier = new KeyIdentifier(aki.getKeyIdentifier());
    }

    GeneralNameList issuerNames = null;
    if (aki.getAuthorityCertIssuer() != null) {
      issuerNames = createGeneralNameList(aki.getAuthorityCertIssuer());
    }

    Integer issuerSerial = null;
    if (aki.getAuthorityCertSerialNumber() != null) {
      issuerSerial = aki.getAuthorityCertSerialNumber().intValue();
    }
    return new AuthorityKeyIdentifier(keyIdentifier, issuerNames, issuerSerial);
  }


  /**
   * Creates a {@link KeyUsage} object from DER data.
   *
   * @param  enc  DER encoded key usage data.
   *
   * @return  Key usage data.
   */
  public static KeyUsage createKeyUsage(final DEREncodable enc)
  {
    final DERBitString usage = org.bouncycastle.asn1.x509.KeyUsage.getInstance(
      enc);
    return new KeyUsage(usage.getBytes());
  }


  /**
   * Creates a {@link KeyPurposeIdList} object from DER data.
   *
   * @param  enc  DER encoded key purpose identifier data.
   *
   * @return  Key purpose ID list object.
   */
  public static KeyPurposeIdList createKeyPurposeIdList(final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.ExtendedKeyUsage usages =
      org.bouncycastle.asn1.x509.ExtendedKeyUsage.getInstance(enc);
    final List idList = new ArrayList();
    for (Object usage : usages.getUsages()) {
      idList.add(KeyPurposeId.getByOid(usage.toString()));
    }
    return new KeyPurposeIdList(idList);
  }


  /**
   * Creates a {@link DistributionPointList} object from DER data.
   *
   * @param  enc  DER encoded distribution point list.
   *
   * @return  List of CRL distribution points.
   */
  public static DistributionPointList createDistributionPointList(
    final DEREncodable enc)
  {
    if (!(enc instanceof ASN1Sequence)) {
      throw new IllegalArgumentException(
        "Expected ASN1Sequence but got " + enc);
    }

    final ASN1Sequence seq = (ASN1Sequence) enc;
    final List distPoints =
      new ArrayList();
    for (int i = 0; i < seq.size(); i++) {
      final org.bouncycastle.asn1.x509.DistributionPoint dp =
        org.bouncycastle.asn1.x509.DistributionPoint.getInstance(
          seq.getObjectAt(i));
      Object name = null;
      if (dp.getDistributionPoint() != null) {
        if (
          dp.getDistributionPoint().getType() ==
            org.bouncycastle.asn1.x509.DistributionPointName.FULL_NAME) {
          name = createGeneralNameList(dp.getDistributionPoint().getName());
        } else {
          name = dp.getDistributionPoint().toString();
        }
      }

      ReasonFlags reasons = null;
      if (dp.getReasons() != null) {
        reasons = new ReasonFlags(dp.getReasons().getBytes());
      }

      GeneralNameList issuer = null;
      if (dp.getCRLIssuer() != null) {
        issuer = createGeneralNameList(dp.getCRLIssuer());
      }
      if (name instanceof GeneralNameList) {
        distPoints.add(
          new DistributionPoint((GeneralNameList) name, reasons, issuer));
      } else {
        distPoints.add(new DistributionPoint((String) name, reasons, issuer));
      }
    }
    return new DistributionPointList(distPoints);
  }


  /**
   * Creates a {@link AccessDescriptionList} object from DER data.
   *
   * @param  enc  DER encoded distribution point list.
   *
   * @return  List of access descriptions.
   */
  public static AccessDescriptionList createAccessDescriptionList(
    final DEREncodable enc)
  {
    final org.bouncycastle.asn1.x509.AuthorityInformationAccess info =
      org.bouncycastle.asn1.x509.AuthorityInformationAccess.getInstance(enc);
    final List accessDescList =
      new ArrayList();
    for (
      org.bouncycastle.asn1.x509.AccessDescription desc :
        info.getAccessDescriptions()) {
      accessDescList.add(
        new AccessDescription(
          AccessMethod.getByOid(desc.getAccessMethod().toString()),
          createGeneralName(desc.getAccessLocation())));
    }
    return new AccessDescriptionList(accessDescList);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy