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

se.idsec.utils.printcert.display.DisplayCert Maven / Gradle / Ivy

/*
 * Copyright (c) 2021. IDsec Solutions AB (IDsec)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.idsec.utils.printcert.display;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.Attribute;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.GeneralSubtree;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.NameConstraints;
import org.bouncycastle.asn1.x509.PolicyConstraints;
import org.bouncycastle.asn1.x509.PolicyMappings;
import org.bouncycastle.asn1.x509.PrivateKeyUsagePeriod;
import org.bouncycastle.asn1.x509.SubjectDirectoryAttributes;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.qualified.BiometricData;
import org.bouncycastle.util.encoders.Hex;
import org.w3c.dom.Element;

import se.idsec.utils.printcert.PrintCertificate;
import se.idsec.utils.printcert.data.SubjectAttributeInfo;
import se.idsec.utils.printcert.display.html.TableElement;
import se.idsec.utils.printcert.enums.OidName;
import se.idsec.utils.printcert.enums.SubjectDnType;
import se.idsec.utils.printcert.enums.SupportedExtension;
import se.idsec.utils.printcert.extension.ExtensionInfo;
import se.idsec.utils.printcert.utils.CertUtils;
import se.swedenconnect.cert.extensions.AuthnContext;
import se.swedenconnect.cert.extensions.BiometricInfo;
import se.swedenconnect.cert.extensions.InhibitAnyPolicy;
import se.swedenconnect.cert.extensions.QCStatements;
import se.swedenconnect.cert.extensions.SubjectInformationAccess;
import se.swedenconnect.cert.extensions.data.MonetaryValue;
import se.swedenconnect.cert.extensions.data.PDSLocation;
import se.swedenconnect.cert.extensions.data.SemanticsInformation;
import se.swedenconnect.cert.extensions.data.saci.AttributeMapping;
import se.swedenconnect.cert.extensions.data.saci.AuthContextInfo;
import se.swedenconnect.cert.extensions.data.saci.IdAttributes;
import se.swedenconnect.cert.extensions.data.saci.SAMLAuthContext;

/**
 * @author stefan
 */
public class DisplayCert {

  /** Formatter for XML date element content */
  public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(
    "yyyy-MM-dd HH:mm:ss z",
    Locale.ENGLISH).withZone(ZoneId.systemDefault());

  /**
   * The default cert display table class names for html print.
   */
  public static final CertTableClasses DEF_TABLE_CLASSES = new CertTableClasses(
    "table table-sm cert-table",
    "table table-sm cert-table-head",
    "subjectDNTable",
    new String[] { "certTableHeadRow", "certTableHead" },
    new String[] { "certTableValueRow", "certTableParam", "cerTableValue" },
    new String[] { "certTableExtHeadRow", "certTableExtHead" },
    new String[] { "certTableExtValueRow", "certTableExtParam", "cerTableExtValue" },
    new String[] { "certTableExtSubValueRow", "certTableExtSubParam", "cerTableExtSubValue" },
    new String[] { "certTableValueRow", "certTableExtParam", "cerTableExtValue" },
    new String[] { "certTableValueRow", "certTableExtParam", "cerTableMonospaceVal" },
    new String[] { "subjectDNRow", "subjectDNParam", "subjectDNVal" }
  );
  private static final String[] generalNameTagText = new String[] {
    "Other Name",
    "E-Mail",
    "DNS",
    "x400Address",
    "Directory Name",
    "EDI Party Name",
    "URI",
    "IP Address",
    "Registered ID" };
  private static final String[] verboseParams = new String[] {
    "modulus",
    "public x coord",
    "public y coord"
  };

  public static String certToDisplayString(PrintCertificate cert, boolean monospace, boolean verbose, boolean decode) {
    StringBuilder b = new StringBuilder();
    List dispList = new ArrayList<>();
    dispList.add(getCertFieldDispData(cert, verbose, decode, false));
    List extensionInfoList = cert.getExtensionInfoList();
    for (int i = 0; i < extensionInfoList.size(); i++) {
      try {
        UnitDisplayData extensionPrintData = getExtensionPrintData(extensionInfoList.get(i), i);
        dispList.add(extensionPrintData);
      }
      catch (IOException ex) {
        Logger.getLogger(DisplayCert.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
    dispList.add(getCertSignData(cert, verbose));

    b.append("X.509 Certificate {\n");
    for (UnitDisplayData dispData : dispList) {
      b.append(getTextDisplay(dispData, monospace)).append("\n");
    }
    b.append("}");

    return b.toString();

  }

  public static String certToHtmlString(PrintCertificate cert, String heading, boolean verbose) {
    return certToHtmlString(cert, heading, DEF_TABLE_CLASSES, verbose, true);
  }

  public static String certToHtmlString(PrintCertificate cert, String heading, boolean verbose, boolean decode) {
    return certToHtmlString(cert, heading, DEF_TABLE_CLASSES, verbose, decode);
  }

  public static String certToHtmlString(PrintCertificate cert, String heading, CertTableClasses tableClasses, boolean verbose,
    boolean decode) {
    List dispList = new ArrayList<>();
    dispList.add(getCertFieldDispData(cert, verbose, decode, true));
    List extensionInfoList = cert.getExtensionInfoList();
    for (int i = 0; i < extensionInfoList.size(); i++) {
      try {
        UnitDisplayData extensionPrintData = getExtensionPrintData(extensionInfoList.get(i), i);
        dispList.add(extensionPrintData);
      }
      catch (IOException ex) {
        Logger.getLogger(DisplayCert.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
    dispList.add(getCertSignData(cert, verbose));
    return getHtmlDisplay(dispList, heading, tableClasses);

  }

  private static UnitDisplayData getExtensionPrintData(ExtensionInfo extInfo, int idx) throws IOException {
    return getExtensionPrintData(extInfo.getOid(), extInfo.getExtDataASN1(), extInfo.isCritical(), extInfo.getExtData(), idx);
  }

  private static UnitDisplayData getExtensionPrintData(ASN1ObjectIdentifier oid, ASN1Primitive extDataASN1, boolean critical, byte[] bytes,
    int idx) throws IOException {
    SupportedExtension extension = SupportedExtension.getExtension(oid);
    List da = new ArrayList<>();

    switch (extension) {
    case basicConstraints:
      BasicConstraints ext = BasicConstraints.getInstance(extDataASN1);
      da.add(new String[] { "CA", String.valueOf(ext.isCA()) });
      if (ext.getPathLenConstraint() != null) {
        da.add(new String[] { "PathLen", ext.getPathLenConstraint().toString() });
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case authorityInfoAccess:
      AuthorityInformationAccess aia = AuthorityInformationAccess.getInstance(extDataASN1);
      AccessDescription[] aiadescArray = aia.getAccessDescriptions();
      if (aiadescArray != null) {
        for (int i = 0; i < aiadescArray.length; i++) {
          da.add(new String[] { "accessMethod" + getIndexStr(i), OidName.getName(aiadescArray[i].getAccessMethod().getId()) });
          da.add(new String[] { "  accessLocation", getGeneralNameStr(aiadescArray[i].getAccessLocation()) });
        }
      }
      return new UnitDisplayData(extension, idx, critical, da);
    //return new UnitDisplayData(extension, idx, critical, new AuthorityInfoAccessExtension(critical, bytes).toString(), true);
    case authorityKeyIdentifier:
      AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(extDataASN1);
      byte[] keyIdentifier = aki.getKeyIdentifier();
      BigInteger authorityCertSerialNumber = aki.getAuthorityCertSerialNumber();
      GeneralNames authorityCertIssuer = aki.getAuthorityCertIssuer();
      if (keyIdentifier != null) {
        da.add(new String[] { "Key identifier", byteArrayToHexString(keyIdentifier) });
      }
      if (authorityCertIssuer != null) {
        da.add(new String[] { "Cert Issuer", getGeneralNamesString(authorityCertIssuer) });
      }
      if (authorityCertSerialNumber != null) {
        da.add(new String[] { "Cert serial", authorityCertSerialNumber.toString(16) });
      }
      return new UnitDisplayData(extension, idx, critical, da);
    //return new UnitDisplayData(extension, idx, critical, new AuthorityKeyIdentifierExtension(critical, bytes).toString(), true);
    case biometricInfo:
      BiometricInfo biometricInfo = BiometricInfo.getInstance(extDataASN1);
      List biometricDataList = biometricInfo.getBiometricDataList();
      for (int bdIdx = 0; bdIdx < biometricDataList.size(); bdIdx++) {
        BiometricData biometricData = biometricDataList.get(bdIdx);

        da.add(new String[] { "Biometric data" + getIndexStr(bdIdx),
          "Type: " + BiometricInfo.getTypeString(biometricData.getTypeOfBiometricData()) });
        da.add(new String[] { "  Hash algoritm", biometricData.getHashAlgorithm().getAlgorithm().getId() });
        da.add(new String[] { "  Hash value", Hex.toHexString(biometricData.getBiometricDataHash().getOctets()) });
        if (biometricData.getSourceDataUriIA5() != null) {
          da.add(new String[] { "  Source UIR", biometricData.getSourceDataUriIA5().getString() });
        }
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case cRLDistributionPoints:
      CRLDistPoint crldp = CRLDistPoint.getInstance(extDataASN1);
      DistributionPoint[] distributionPoints = crldp.getDistributionPoints();
      if (distributionPoints != null) {
        for (int dpIdx = 0; dpIdx < distributionPoints.length; dpIdx++) {
          DistributionPointName dpn = distributionPoints[dpIdx].getDistributionPoint();
          try {
            GeneralNames dpGns = (GeneralNames) dpn.getName();
            GeneralName[] names = dpGns.getNames();
            for (int i = 0; i < names.length; i++) {
              da.add(new String[] { "DistributionPoint" + getIndexStr(dpIdx), getGeneralNameStr(names[i]) });
            }
          }
          catch (Exception ex) {
          }
        }
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case certificateIssuer:
      return new UnitDisplayData(extension, idx, critical, null, false);
    case certificatePolicies:
      CertificatePolicies cp = CertificatePolicies.getInstance(extDataASN1);
      getPolicyText(cp, da);
      return new UnitDisplayData(extension, idx, critical, da);
    //return new UnitDisplayData(extension, idx, critical, new CertificatePoliciesExtension(critical, bytes).toString(), true);
    case extendedKeyUsage:
      ExtendedKeyUsage eku = ExtendedKeyUsage.getInstance(extDataASN1);
      KeyPurposeId[] usages = eku.getUsages();
      if (usages != null) {
        for (int i = 0; i < usages.length; i++) {
          da.add(new String[] { "KeyPurposeId " + getIndexStr(i), OidName.getName(usages[i].getId()) });
        }
      }
      return new UnitDisplayData(extension, idx, critical, da);
    //return new UnitDisplayData(extension, idx, critical, new ExtendedKeyUsageExtension(critical, bytes).toString(), true);
    case issuerAlternativeName:
      GeneralNames ian = GeneralNames.getInstance(extDataASN1);
      if (ian != null) {
        getAltNameExtensionDisp(ian, da);
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case keyUsage:
      KeyUsage keyUsage = KeyUsage.getInstance(extDataASN1);
      getKeyUsageText(keyUsage, da);
      return new UnitDisplayData(extension, idx, critical, da);
    case netscapeCertType:
      KeyUsage nsct = KeyUsage.getInstance(extDataASN1);
      getNetscapeCertTypeText(nsct, da);
      return new UnitDisplayData(extension, idx, critical, da);
    case logoType:
      return new UnitDisplayData(extension, idx, critical, null, false);
    case inhibitAnyPolicy:
      getInhibitAnyPolicyText(InhibitAnyPolicy.getInstance(bytes), da);
      return new UnitDisplayData(extension, idx, critical, da);
    case nameConstraints:
      getNameConstraintsText(NameConstraints.getInstance(bytes), da);
      return new UnitDisplayData(extension, idx, critical, da);
    case policyConstraints:
      getPolicyConstraintsText(PolicyConstraints.getInstance(bytes), da);
      return new UnitDisplayData(extension, idx, critical, da);
    case policyMappings:
      getPolicyMappingsText(PolicyMappings.getInstance(bytes), da);
      return new UnitDisplayData(extension, idx, critical, da);
    case privateKeyUsagePeriod:
      PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod.getInstance(extDataASN1);
      if (pkup.getNotBefore() != null) {
        try {
          da.add(new String[] { "NotBefore ", DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(pkup.getNotBefore().getDate().getTime())) });
        }
        catch (ParseException e) {
          da.add(new String[]{"NotBefore ", "Illegal time data"});
        }
      }
      if (pkup.getNotAfter() != null) {
        try {
          da.add(new String[] { "NotAfter ", DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(pkup.getNotAfter().getDate().getTime())) });
        } catch (ParseException e) {
          da.add(new String[]{"NotBefore ", "Illegal time data"});
        }
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case qCStatements:
      //b.append("ObjectId: ").append(oid.getId()).append(" Criticality=").append(critical).append("\n");
      QCStatements qcstatements = QCStatements.getInstance(extDataASN1);
      getQcStatementsDisp(qcstatements, da);
      return new UnitDisplayData(extension, idx, critical, da);
    //b.append(QCStatementsExt.getInstance(extDataASN1).toString());
    //return new UnitDisplayData(extension, idx, critical, b.toString(), false);
    case subjectAlternativeName:
      GeneralNames san = GeneralNames.getInstance(extDataASN1);
      if (san != null) {
        getAltNameExtensionDisp(san, da);
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case subjectDirectoryAttributes:
      SubjectDirectoryAttributes subjectDirectoryAttributes = SubjectDirectoryAttributes.getInstance(extDataASN1);
      try {
        @SuppressWarnings("unchecked")
        Vector attributes = subjectDirectoryAttributes.getAttributes();
        for (Attribute attribute : attributes) {
          List valueList = Arrays.stream(attribute.getAttributeValues())
            .map(asn1Encodable -> getStringValue(asn1Encodable))
            .collect(Collectors.toList());
          ASN1ObjectIdentifier attrType = attribute.getAttrType();
          SubjectDnType subjectDnType = SubjectDnType.getNameTypeForOid(attrType);
          String attrName = subjectDnType.getOidString() == null
            ? attrType.getId()
            : subjectDnType.getDispName();
          if (!valueList.isEmpty()) {
            String displayValue = valueList.size() == 1
              ? valueList.get(0)
              : "[ " + String.join(", ", valueList) + " ]";
            da.add(new String[] { attrName, displayValue });
          }
        }
      } catch (Exception ex) {
        return new UnitDisplayData(extension, idx, critical, SubjectDirectoryAttributes.getInstance(extDataASN1).toString(), true);
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case subjectInfoAccess:
      SubjectInformationAccess sia = SubjectInformationAccess.getInstance(extDataASN1);
      AccessDescription[] siadescArray = sia.getAccessDescriptions();
      if (siadescArray != null) {
        for (int i = 0; i < siadescArray.length; i++) {
          da.add(new String[] { "accessMethod" + getIndexStr(i), OidName.getName(siadescArray[i].getAccessMethod().getId()) });
          da.add(new String[] { "  accessLocation", getGeneralNameStr(siadescArray[i].getAccessLocation()) });
        }
      }
      return new UnitDisplayData(extension, idx, critical, da);
    case subjectKeyIdentifier:
      SubjectKeyIdentifier ski = SubjectKeyIdentifier.getInstance(extDataASN1);
      byte[] skeyIdentifier = ski.getKeyIdentifier();
      if (skeyIdentifier != null) {
        da.add(new String[] { "Key identifier", byteArrayToHexString(skeyIdentifier) });
      }
      return new UnitDisplayData(extension, idx, critical, da);
    //return new UnitDisplayData(extension, idx, critical, new SubjectKeyIdentifierExtension(critical, bytes).toString(), true);
    case ocspNocheck:
      da.add(new String[] { "OCSP no-check", "true" });
      return new UnitDisplayData(extension, idx, critical, da);
      //return new UnitDisplayData(extension, idx, critical, new OCSPNoCheckExtension(critical, bytes).toString(), true);
    case authContext:
      AuthnContext authCont = AuthnContext.getInstance(extDataASN1);
      getAuthnContextDisp(authCont, da);
      return new UnitDisplayData(extension, idx, critical, da);
    //b.append(AuthnContext.getInstance(extDataASN1));
    //return new UnitDisplayData(extension, idx, critical, b.toString(), false);
    case unknown:
      UnitDisplayData unknownData = new UnitDisplayData(UnitType.extension);
      unknownData.setCriticality(critical);
      unknownData.setId(oid.getId());
      unknownData.setSequence(idx);
      unknownData.setName("Unkown extension");
      unknownData.setStructured(false);
      unknownData.setFreeText("Unknown data structure with " + String.valueOf(bytes.length) + " bytes of data");
      return unknownData;
    case signedCertificateTimestampList:
      da.add(new String[] { "SignedTimeStampList", String.valueOf(bytes.length) + " bytes of data" });
      return new UnitDisplayData(extension, idx, critical, da);
    default:
      throw new AssertionError(extension.name());

    }
  }

  private static UnitDisplayData getCertFieldDispData(PrintCertificate cert, boolean verbose, boolean decode, boolean html) {
    UnitDisplayData udd = new UnitDisplayData(UnitType.certFields);
    udd.setStructured(true);
    List dataArray = new ArrayList<>();
    dataArray.add(new String[] { "Version", String.valueOf(cert.getVersionNumber()) });
    dataArray.add(new String[] { "Serial number", cert.getSerialNumber().toString(16) });
    dataArray.add(new String[] { "Issuer", getCertNameFieldPrint(cert.getIssuer(), decode, html) });
    dataArray.add(new String[] { "Not valid before", cert.getNotBefore().toString() });
    dataArray.add(new String[] { "Not valid after", cert.getNotAfter().toString() });
    dataArray.add(new String[] { "Subject", getCertNameFieldPrint(cert.getSubject(), decode, html) });

    //Extract public key info from oiginal print.
    List textLines = CertUtils.getTextLines(cert.toOriginalString());
    boolean pkStart = false, pkEnd = false;
    for (String line : textLines) {
      if (line.trim().startsWith("Public Key:")) {
        pkStart = true;
      }
      if (pkStart && line.trim().length()==0) {
        pkEnd = true;
      }
      if (pkStart && !pkEnd) {
        line = line.trim();
        String[] split = line.split(":");
        int len = split.length;
        if (len > 1) {
          if (verbose || !isVerbose(split[0])) {
            if (len == 2){
              dataArray.add(new String[] { split[0].trim(), split[1].trim() });
            } else {
              dataArray.add(new String[] { line.substring(0, line.indexOf(":")), line.substring(line.indexOf(":")+2) });
            }
          }
        }
        if (len == 1) {
          dataArray.add(new String[] { "parameter", line.trim() });
        }
      }
    }

    try {
      //Add fingerprint
      MessageDigest md = MessageDigest.getInstance("SHA-1");
      byte[] digest = md.digest(cert.getEncoded());
      //dataArray.add(new String[] { "", "" });
      dataArray.add(new String[] { "SHA1 Fingerprint", byteArrayToHexString(digest) });

    }
    catch (NoSuchAlgorithmException ex) {
      Logger.getLogger(DisplayCert.class.getName()).log(Level.SEVERE, null, ex);
    }

    udd.setDataArray(dataArray);
    return udd;
  }

  private static boolean isVerbose(String string) {
    for (String verboseStr : verboseParams) {
      if (string.equalsIgnoreCase(verboseStr)) {
        return true;
      }
    }
    return false;
  }

  private static UnitDisplayData getCertSignData(PrintCertificate cert, boolean verbose) {
    List textLines = CertUtils.getTextLines(cert.toOriginalString());
    UnitDisplayData dispData = new UnitDisplayData(UnitType.signature);
    StringBuilder b = new StringBuilder();
    int i = 0;
    int algoStart = -1;
    List da = new ArrayList<>();
    // Loop through all cert lines
    while (i < textLines.size()) {
      String line = textLines.get(i);
      if (line.trim().startsWith("Signature Algorithm:")) {
        algoStart = i;
        break;
      }
      i++;
    }


    boolean display=false;
    if (verbose) {
      String sigAlgo = "";
      if (algoStart > -1) {
        for (int j = algoStart; j < textLines.size(); j++) {
          String line = textLines.get(j);
          if (line.trim().toLowerCase().startsWith("extensions")){
            break;
          }
          if (j == algoStart){
            sigAlgo = line.trim().substring(21);
          }
          if (j == algoStart+1){
            b.append(line.trim().substring(11));
          }
          if (j > algoStart +1){
            b.append(line.trim());
          }

        }
        dispData.setStructured(true);
        da.add(new String[] { "Signature Algorithm", sigAlgo});
        da.add(new String[] { "Signature", b.toString()});
        dispData.setDataArray(da);
        display=true;
      }
    }
    else {
      if (algoStart > -1) {
        try {
          da.add(new String[] { "Algorithm", textLines.get(algoStart).trim().substring(20).trim()});
          dispData.setStructured(true);
          dispData.setDataArray(da);
          display=true;
        } catch (Exception ex){
          Logger.getLogger(DisplayCert.class.getName()).fine("Failed to parse Algorithm data in certificate");
        }
      }
    }

    if (!display){
      dispData.setStructured(false);
      dispData.setFreeText("Unable to parse algorithm and signature data");
    }

    return dispData;

  }

  private static String getTextDisplay(UnitDisplayData dispData, boolean monospace) {
    StringBuilder b = new StringBuilder();
    int maxLen = -1;
    List dataArray = dispData.getDataArray();
    if (dispData.isStructured() && monospace) {
      maxLen = getMaxLen(dispData.getDataArray());
    }

    UnitType type = dispData.getType();
    switch (type) {
    case certFields:
      for (String[] strArray : dataArray) {
        if (strArray[0].length() + strArray[1].length() > 0) {
          b.append(strArray[0]).append(getSpc(maxLen - strArray[0].length())).append(": ").append(strArray[1]).append("\n");
        }
        else {
          b.append("\n");
        }
      }
      break;
    case extension:
      b.append("Extension ").append(dispData.getSequence() + 1).append(":   ");
      if (!dispData.isHasPrefix()) {
        b.append(dispData.isCriticality() ? "critical   " : "not critical   ");
        b.append(dispData.getName()).append(" (").append(dispData.getId()).append(")\n");
      }
      if (dispData.isStructured()) {
        for (String[] strArray : dataArray) {
          if (strArray[0].length() + strArray[1].length() > 0) {
            b.append("  ").append(strArray[0]).append(getSpc(maxLen - strArray[0].length())).append(": ").append(strArray[1]).append("\n");
          }
          else {
            b.append("\n");
          }
        }
      }
      else {
        b.append("  ").append(dispData.getFreeText().trim()).append("\n");
      }
      break;
    case signature:
      b.append("Certificate Signature:\n");
      if (dispData.isStructured()) {
        for (String[] strArray : dataArray) {
          if (strArray[0].length() + strArray[1].length() > 0) {
            b.append(strArray[0]).append(getSpc(maxLen - strArray[0].length())).append(": ").append(strArray[1]).append("\n");
          }
          else {
            b.append("\n");
          }
        }
      }
      else {
        b.append(dispData.getFreeText().trim()).append("\n");
      }
      break;
    default:
      throw new AssertionError(type.name());

    }
    return b.toString();

  }

  public static String byteArrayToHexString(byte[] b) {
    String result = "";
    for (int i = 0; i < b.length; i++) {
      result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
      if ((i + 1) < b.length) {
        result += ":";
      }
    }
    return result;
  }

  private static int getMaxLen(List dataArray) {
    int max = -1;
    for (String[] strArray : dataArray) {
      int arraySize = strArray.length;
      if (arraySize > 0) {
        String str = strArray[0];
        if (str.length() > max) {
          max = str.length();
        }
      }
    }
    return max;
  }

  private static String getSpc(int len) {
    String spcStr = "";
    for (int i = 0; i < len; i++) {
      spcStr += " ";
    }
    return spcStr;
  }

  private static String getGeneralNamesString(GeneralNames genNames) {
    GeneralName[] names = genNames.getNames();
    StringBuilder b = new StringBuilder();
    b.append("GeneralNames {");
    for (int i = 0; i < names.length; i++) {
      b.append(getGeneralNameStr(names[i]));
      if (i + 1 < names.length) {
        b.append(" | ");
      }
    }
    b.append("}");
    return b.toString();
  }

  public static String getGeneralNameStr(GeneralName generalName) {
    if (generalName == null) {
      return "null";
    }
    String toString = generalName.toString();
    try {
      int tagNo = Integer.valueOf(toString.substring(0, toString.indexOf(":")));
      return generalNameTagText[tagNo] + toString.substring(toString.indexOf(":"));

    }
    catch (Exception e) {
      return toString;
    }
  }

  private static void getPolicyText(CertificatePolicies cp, List da) {
    try {
      ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(cp.getEncoded()));
      ASN1Sequence polInfoSeq = ASN1Sequence.getInstance(din.readObject());
      for (int i = 0; i < polInfoSeq.size(); i++) {
        ASN1Sequence polSeq = ASN1Sequence.getInstance(polInfoSeq.getObjectAt(i));
        ASN1ObjectIdentifier policyId = ASN1ObjectIdentifier.getInstance(polSeq.getObjectAt(0));
        da.add(new String[] { "certificatePolicy" + getIndexStr(i), OidName.getName(policyId.getId()) });
        if (polSeq.size() > 1) {
          ASN1Sequence qualSeq = ASN1Sequence.getInstance(polSeq.getObjectAt(1));
          for (int qualifierIdx = 0; qualifierIdx < qualSeq.size(); qualifierIdx++) {
            ASN1Sequence qualInfoSeq = ASN1Sequence.getInstance(qualSeq.getObjectAt(qualifierIdx));
            ASN1ObjectIdentifier qualifierId = ASN1ObjectIdentifier.getInstance(qualInfoSeq.getObjectAt(0));
            da.add(new String[] { "  qualifier" + getIndexStr(qualifierIdx), OidName.getName(qualifierId.getId()) });
            if (qualifierId.getId().equalsIgnoreCase(OidName.cpsQualifier.getOid())) {
              da.add(new String[] { "  - CPS URI", DERIA5String.getInstance(qualInfoSeq.getObjectAt(1)).getString() });
            }
            if (qualifierId.getId().equalsIgnoreCase(OidName.usernoticeQualifier.getOid())) {
              da.add(new String[] { "  - User Notice", qualInfoSeq.getObjectAt(1).toString() });
            }
          }
        }

      }

    }
    catch (IOException ex) {
      Logger.getLogger(DisplayCert.class.getName()).log(Level.SEVERE, null, ex);
    }

  }

  private static void getKeyUsageText(KeyUsage keyUsage, List da) {
    da.add(new String[] { "Usage", getKeyUsageText(keyUsage) });

  }

  public static String getKeyUsageText(KeyUsage keyUsage) {
    List usagesList = new ArrayList<>();
    StringBuilder b = new StringBuilder();
    if (keyUsage.hasUsages(KeyUsage.digitalSignature)) {
      usagesList.add("digitalSignature");
    }
    if (keyUsage.hasUsages(KeyUsage.nonRepudiation)) {
      usagesList.add("nonRepudiation");
    }
    if (keyUsage.hasUsages(KeyUsage.keyEncipherment)) {
      usagesList.add("keyEncipherment");
    }
    if (keyUsage.hasUsages(KeyUsage.dataEncipherment)) {
      usagesList.add("dataEncipherment");
    }
    if (keyUsage.hasUsages(KeyUsage.keyAgreement)) {
      usagesList.add("keyAgreement");
    }
    if (keyUsage.hasUsages(KeyUsage.keyCertSign)) {
      usagesList.add("keyCertSign");
    }
    if (keyUsage.hasUsages(KeyUsage.cRLSign)) {
      usagesList.add("cRLSign");
    }
    if (keyUsage.hasUsages(KeyUsage.encipherOnly)) {
      usagesList.add("encipherOnly");
    }
    if (keyUsage.hasUsages(KeyUsage.decipherOnly)) {
      usagesList.add("decipherOnly");
    }
    for (int i = 0; i < usagesList.size(); i++) {
      b.append(usagesList.get(i));
      if (i + 1 < usagesList.size()) {
        b.append(" | ");
      }
    }
    return b.toString();
  }

  private static void getNetscapeCertTypeText(KeyUsage keyUsage, List da) {
    List usagesList = new ArrayList<>();
    StringBuilder b = new StringBuilder();
    if (keyUsage.hasUsages(KeyUsage.digitalSignature)) {
      usagesList.add("SSL Client");
    }
    if (keyUsage.hasUsages(KeyUsage.nonRepudiation)) {
      usagesList.add("SSL Server");
    }
    if (keyUsage.hasUsages(KeyUsage.keyEncipherment)) {
      usagesList.add("S/MIME");
    }
    if (keyUsage.hasUsages(KeyUsage.dataEncipherment)) {
      usagesList.add("Object-signing");
    }
    if (keyUsage.hasUsages(KeyUsage.keyAgreement)) {
      usagesList.add("Reserved");
    }
    if (keyUsage.hasUsages(KeyUsage.keyCertSign)) {
      usagesList.add("SSL-CA");
    }
    if (keyUsage.hasUsages(KeyUsage.cRLSign)) {
      usagesList.add("S/MIME CA");
    }
    if (keyUsage.hasUsages(KeyUsage.encipherOnly)) {
      usagesList.add("Object-signing CA");
    }
    for (int i = 0; i < usagesList.size(); i++) {
      b.append(usagesList.get(i));
      if (i + 1 < usagesList.size()) {
        b.append(" | ");
      }
    }
    da.add(new String[] { "CertType", b.toString() });
  }

  private static void getAuthnContextDisp(AuthnContext authCont, List da) {
    List statementInfoList = authCont.getStatementInfoList();
    for (int stIdx = 0; stIdx < statementInfoList.size(); stIdx++) {
      da.add(new String[] { "SAMLAuthContext" + getIndexStr(stIdx), "http://id.elegnamnden.se/auth-cont/1.0/saci" });
      SAMLAuthContext samlAuthContext = statementInfoList.get(stIdx);
      try {
        AuthContextInfo aci = samlAuthContext.getAuthContextInfo();
        addDispItem(aci.getIdentityProvider(), "  Identity Provider", da);
        addDispItem(aci.getAuthnContextClassRef(), "  Level of Assurance", da);
        addDispItem(DATE_TIME_FORMATTER.format(aci.getAuthenticationInstant()), "  Authn Instant", da);
        addDispItem(aci.getAssertionRef(), "  Assertion Ref", da);
        addDispItem(aci.getServiceID(), "  ServiceID", da);

        IdAttributes idAttributes = samlAuthContext.getIdAttributes();
        if (idAttributes != null) {
          List attributeMappingList = idAttributes.getAttributeMappings();
          for (int amIdx = 0; amIdx < attributeMappingList.size(); amIdx++) {
            AttributeMapping amt = attributeMappingList.get(amIdx);
            String ref = amt.getRef();
            String type = amt.getType().toString();
            if (type.equalsIgnoreCase("san")) {
              try {
                ref = generalNameTagText[Integer.valueOf(ref)];
              }
              catch (Exception e) {
              }
            }
            String name = amt.getAttribute().getName();
            String friendlyName = amt.getAttribute().getFriendlyName();
            String friendlyNameString = friendlyName != null ? " | " + friendlyName : "";
            List attributeValues = amt.getAttribute().getAttributeValues();
            String attributeValueString = "";
            if (attributeValues != null && !attributeValues.isEmpty()){
              attributeValueString = " (" + attributeValues.get(0).getTextContent() + ")";
            }
            String val = "SAML: " + name + friendlyNameString + " --> Type=" + type + " Ref=" + ref + attributeValueString;
            addDispItem(val, "  Attribute mapping " + String.valueOf(amIdx), da);
          }
        }

      }
      catch (Exception e) {
      }
    }
  }

  private static void addDispItem(Object value, String name, List da) {
    StringBuilder b = new StringBuilder();
    if (value != null) {
      b.append(value);
      if (b.length() > 0) {
        da.add(new String[] { name, b.toString() });
      }
    }
  }

  private static void getAltNameExtensionDisp(GeneralNames san, List da) {
    GeneralName[] names = san.getNames();
    if (names != null) {
      for (GeneralName name : names) {
        String toString = name.toString();
        try {
          int tagNo = Integer.valueOf(toString.substring(0, toString.indexOf(":")));
          da.add(new String[] { generalNameTagText[tagNo], toString.substring(toString.indexOf(":") + 1) });

        }
        catch (Exception e) {
        }
      }
    }
  }

  private static void getPolicyMappingsText(PolicyMappings instance, List da) {

    final ASN1Sequence pmSeq = (ASN1Sequence) instance.toASN1Primitive();
    final Iterator iterator = pmSeq.iterator();
    while (iterator.hasNext()){
      ASN1Sequence oidSeq = ASN1Sequence.getInstance(iterator.next());
      String idp = ASN1ObjectIdentifier.getInstance(oidSeq.getObjectAt(0)).getId();
      String sdp = ASN1ObjectIdentifier.getInstance(oidSeq.getObjectAt(0)).getId();
      da.add(new String[]{"Mapping", "issuer: " + idp + " --> subject: " + sdp});
    }
  }

  private static void getPolicyConstraintsText(PolicyConstraints instance, List da) {

    final BigInteger requireExplicitPolicyMapping = instance.getRequireExplicitPolicyMapping();
    if (requireExplicitPolicyMapping != null){
      da.add(new String[]{"Require explicit", requireExplicitPolicyMapping.toString()});
    }
    final BigInteger inhibitPolicyMapping = instance.getInhibitPolicyMapping();
    if (inhibitPolicyMapping != null) {
      da.add(new String[]{"Inhibit mapping", inhibitPolicyMapping.toString()});
    }
  }

  private static void getNameConstraintsText(NameConstraints instance, List da) {

    final GeneralSubtree[] permittedSubtrees = instance.getPermittedSubtrees();
    final GeneralSubtree[] excludedSubtrees = instance.getExcludedSubtrees();

    printGeneralSubtree("Permitted Subtree", permittedSubtrees, da);
    printGeneralSubtree("Excluded Subtree", excludedSubtrees, da);
  }

  private static void printGeneralSubtree(String title, GeneralSubtree[] generalSubtreeArray, List da) {
    if (generalSubtreeArray != null && generalSubtreeArray.length > 0 ){
      for (int i = 0; i< generalSubtreeArray.length ; i++){
        GeneralSubtree subtree = generalSubtreeArray[i];
        da.add(new String[]{title + "["+i+"]", getGeneralNameStr(subtree.getBase())});
        if (subtree.getMinimum() != null){
          da.add(new String[]{"  minimum", subtree.getMinimum().toString()});
        }
        if (subtree.getMaximum() != null){
          da.add(new String[]{"  maximum", subtree.getMaximum().toString()});
        }
      }
    }
  }

  private static void getInhibitAnyPolicyText(InhibitAnyPolicy instance, List da) {
    da.add(new String[]{"Skip certs", instance.getSkipCerts().toString()});
  }



  private static String getHtmlDisplay(List dispList, String heading, CertTableClasses tableClasses) {
    StringBuilder htmlStr = new StringBuilder();

    TableElement certTable = new TableElement();
    certTable.addAttribute("class", tableClasses.getTableClasses());

    if (heading != null) {
      TableElement headTable = new TableElement();
      headTable.addAttribute("class", tableClasses.getHeadTableClasses());
      headTable.addRow(heading, tableClasses.getHeadClasses(), 2, true);
      htmlStr.append(headTable);
    }

    for (UnitDisplayData dispData : dispList) {
      List dataArray = dispData.getDataArray();

      UnitType type = dispData.getType();
      switch (type) {
      case certFields:
        for (String[] strArray : dataArray) {
          if (strArray != null && strArray.length > 1) {
            strArray[1] = strArray[1].replaceAll("\n", "
"); } certTable.addRow(strArray, tableClasses.getCertFieldClasses()); } break; case extension: StringBuilder b = new StringBuilder(); b.append("Extension ").append(dispData.getSequence() + 1).append(": "); b.append(dispData.getName()).append(" (").append(dispData.getId()).append(") - "); b.append(dispData.isCriticality() ? "critical " : "not critical "); certTable.addRow(b.toString(), tableClasses.getExtensionHeadClasses(), 2, true); if (dispData.isStructured()) { for (String[] strArray : dataArray) { String param = strArray[0]; if (param.startsWith(" ")) { certTable.addRow(padParam(strArray), tableClasses.getCertExtensionSubDataClasses()); } else { certTable.addRow(strArray, tableClasses.getCertExtensionDataClasses()); } } } else { certTable.addRow(new String[] { "ExtensionData", dispData.getFreeText().replaceAll("\n", "
").trim() }, tableClasses.getCertExtensionDataClasses()); } break; case signature: certTable.addRow("Certificate Signature", tableClasses.getExtensionHeadClasses(), 2, true); if (dispData.isStructured()) { for (String[] strArray : dataArray) { certTable.addRow(strArray, tableClasses.getSignatureDataClassesNorm()); } } else { try { certTable.addRow(new String[] { "Signature value", dispData.getFreeText().trim().replaceAll("\n", "
") }, tableClasses.getSignatureDataClassesVerbose()); } catch (Exception ex) { certTable.addRow(new String[] { "Signature value", "Unable to parse signature value: " + ex.getMessage() }); Logger.getLogger(DisplayCert.class.getName()).warning("Problem parsing signature value - " + ex.getMessage()); } } break; default: throw new AssertionError(type.name()); } } htmlStr.append(certTable); return htmlStr.toString(); } private static void getQcStatementsDisp(QCStatements qcstatements, List da) { int idx = 0; if (qcstatements.isPkixSyntaxV1()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "QC Syntax V1" }); } if (qcstatements.isPkixSyntaxV2()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "QC Syntax V2" }); } if (qcstatements.isPkixSyntaxV1() || qcstatements.isPkixSyntaxV2()) { SemanticsInformation semanticsInfo = qcstatements.getSemanticsInfo(); if (semanticsInfo != null) { if (semanticsInfo.getSemanticsIdentifier() != null) { da.add(new String[] { " SemanticsID", OidName.getName(semanticsInfo.getSemanticsIdentifier().getId()) }); } if (!semanticsInfo.getNameRegistrationAuthorityList().isEmpty()) { semanticsInfo.getNameRegistrationAuthorityList().forEach((name) -> { da.add(new String[] { " NameRegAuth", getGeneralNameStr(name) }); }); } } } if (qcstatements.isQcCompliance()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "Qualified Certificate" }); } if (qcstatements.isQcSscd()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "QC SSCD" }); } if (qcstatements.isQcType()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "QC Type" }); for (ASN1ObjectIdentifier type : qcstatements.getQcTypeIdList()) { if (type.getId().equalsIgnoreCase(QCStatements.QC_TYPE_ELECTRONIC_SIGNATURE.getId())) { da.add(new String[] { " Type", "Electronic Signature" }); } if (type.getId().equalsIgnoreCase(QCStatements.QC_TYPE_ELECTRONIC_SEAL.getId())) { da.add(new String[] { " Type", "Electronic Seal" }); } if (type.getId().equalsIgnoreCase(QCStatements.QC_TYPE_WEBSITE_AUTH.getId())) { da.add(new String[] { " Type", "Website Authentication" }); } } } if (qcstatements.isLimitValue()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "Reliance Limit" }); MonetaryValue monetaryValue = qcstatements.getMonetaryValue(); da.add(new String[] { " Currency", monetaryValue.getCurrency() }); da.add(new String[] { " Amount", monetaryValue.getAmount().toString() }); da.add(new String[] { " Exponent", monetaryValue.getExponent().toString() }); } if (qcstatements.isRetentionPeriod()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "Retention Period" }); da.add(new String[] { " Years", qcstatements.getRetentionPeriodVal().toString() }); } if (qcstatements.isPdsStatement()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "PKI Disclosure Statements" }); for (PDSLocation pdsLoc : qcstatements.getLocationList()) { da.add(new String[] { " Location", "Lang=" + pdsLoc.getLang() + " URL: " + pdsLoc.getUrl() }); } } if (qcstatements.isQcCClegislation()) { da.add(new String[] { "Statement" + getIndexStr(idx++), "QC Legislation Countries" }); for (String country : qcstatements.getLegislationCountryList()) { da.add(new String[] { " Country", country }); } } } private static String[] padParam(String[] strArray) { if (strArray == null || strArray.length < 1) { return strArray; } strArray[0] = "  " + strArray[0]; // if (strArray[0].trim().startsWith("-")) { // strArray[0] = "   - " + strArray[0]; // } else { // strArray[0] = "  " + strArray[0]; // } return strArray; } private static String getIndexStr(int i) { return "[" + String.valueOf(i) + "]"; } private static String getCertNameFieldPrint(X500Name name, boolean decode, boolean html) { List attrInfoList = new ArrayList<>(); try { if (!decode) { return name.toString(); } ASN1InputStream ain = new ASN1InputStream(name.getEncoded()); ASN1Sequence nameSeq = ASN1Sequence.getInstance(ain.readObject()); Iterator subjDnIt = nameSeq.iterator(); while (subjDnIt.hasNext()) { ASN1Set rdnSet = (ASN1Set) subjDnIt.next(); Iterator rdnSetIt = rdnSet.iterator(); while (rdnSetIt.hasNext()) { ASN1Sequence rdnSeq = (ASN1Sequence) rdnSetIt.next(); ASN1ObjectIdentifier rdnOid = (ASN1ObjectIdentifier) rdnSeq.getObjectAt(0); //String oidStr = rdnOid.getId(); ASN1Encodable rdnVal = rdnSeq.getObjectAt(1); String rdnValStr = getStringValue(rdnVal); attrInfoList.add(new SubjectAttributeInfo(rdnOid, rdnValStr)); } } } catch (Exception e) { return "Name parsing Error"; } if (html) { TableElement dnTable = new TableElement(); dnTable.addAttribute("class", DEF_TABLE_CLASSES.getSubjectDNTableClasses()); for (SubjectAttributeInfo attrInfo : attrInfoList) { dnTable.addRow(new String[] { attrInfo.getDispName(), attrInfo.getValue() }, DEF_TABLE_CLASSES.getSubjectDNRowClasses()); } return dnTable.toString(); } else { StringBuilder b = new StringBuilder(); for (int i = 0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy