| /******************************************************************************* |
| * Copyright (c) 2008, 2018 Jay Rosenthal and others. |
| * |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Jay Rosenthal - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.equinox.internal.security.ui; |
| |
| import java.security.MessageDigest; |
| import java.security.PublicKey; |
| import java.security.cert.CertificateParsingException; |
| import java.security.cert.X509Certificate; |
| import java.text.DateFormat; |
| import java.util.*; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| import org.eclipse.jface.viewers.Viewer; |
| import org.eclipse.osgi.util.NLS; |
| |
| /** |
| * X509CertificateAttributeContentProvider |
| * Structured content provided for an <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/security/cert/X509Certificate.html">X509Certificate </a> |
| * object. |
| * <p> |
| * Currently this only supports the attributes exposed directly by X509Certificate. Some commonly used extensions |
| * may not be displayed. Contributions and enhancements are welcomed. |
| * |
| */ |
| public class X509CertificateAttributeContentProvider implements IStructuredContentProvider { |
| |
| private static String LABEL_KEYUSAGE_DIGITALSIGNATURE = "digitalSignature"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_NONREPUDIATION = "nonRepudiation"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_KEYENCIPHERMENT = "keyEncipherment"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_DATAENCIPHERMENT = "dataEncipherment"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_KEYAGREEMENT = "keyAgreement"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_CERTSIGN = "keyCertSign"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_CRLSIGN = "cRLSign"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_ENCIPHERONLY = "encipherOnly"; //$NON-NLS-1$ |
| private static String LABEL_KEYUSAGE_DECIPHERONLY = "decipherOnly"; //$NON-NLS-1$ |
| |
| private ArrayList<X509CertificateAttribute> elements = new ArrayList<>(); |
| private Viewer viewer = null; |
| private static String listDelim = ", "; //$NON-NLS-1$ |
| |
| private static final DateFormat _df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.FULL); |
| |
| // TODO - This is a bit ugly but gets the job done... Maybe this should be a class of it's own ?? |
| private static String keyUsageStrings[] = {LABEL_KEYUSAGE_DIGITALSIGNATURE, LABEL_KEYUSAGE_NONREPUDIATION, LABEL_KEYUSAGE_KEYENCIPHERMENT, LABEL_KEYUSAGE_DATAENCIPHERMENT, LABEL_KEYUSAGE_KEYAGREEMENT, LABEL_KEYUSAGE_CERTSIGN, LABEL_KEYUSAGE_CRLSIGN, LABEL_KEYUSAGE_ENCIPHERONLY, LABEL_KEYUSAGE_DECIPHERONLY}; |
| |
| public X509CertificateAttributeContentProvider() { |
| super(); |
| |
| } |
| |
| public Object[] getElements(Object inputElement) { |
| return elements.toArray(); |
| } |
| |
| public void dispose() { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| public void setSelection(X509Certificate curCert) { |
| |
| inputChanged(viewer, null, curCert); |
| |
| if (viewer != null) |
| viewer.refresh(); |
| } |
| |
| public void clear(boolean refresh) { |
| elements.clear(); |
| if (refresh && viewer != null) |
| viewer.refresh(); |
| } |
| |
| public void clear() { |
| clear(true); |
| } |
| |
| public void inputChanged(Viewer aViewer, Object oldInput, Object newInput) { |
| viewer = aViewer; |
| clear(false); // clear the viewer. |
| |
| // Be safe ... check the input |
| if (newInput instanceof X509Certificate) { |
| |
| X509Certificate theCert = (X509Certificate) newInput; |
| |
| X509CertificateAttribute ver = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_VERSION, Integer.valueOf(theCert.getVersion()).toString()); |
| elements.add(ver); |
| |
| X509CertificateAttribute serialNum = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_SERIAL_NUM, theCert.getSerialNumber().toString()); |
| elements.add(serialNum); |
| |
| X509CertificateAttribute validFrom = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_VALID_FROM, _df.format(theCert.getNotBefore()), theCert.getNotBefore()); |
| elements.add(validFrom); |
| |
| X509CertificateAttribute validTo = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_VALID_TO, _df.format(theCert.getNotAfter()), theCert.getNotAfter()); |
| elements.add(validTo); |
| |
| X509CertificateAttribute issuedBy = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_ISSUED_BY, theCert.getIssuerX500Principal().getName(), theCert.getIssuerX500Principal()); |
| elements.add(issuedBy); |
| |
| X509CertificateAttribute IssuedToItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_ISSUED_TO, theCert.getSubjectX500Principal().getName(), theCert.getSubjectX500Principal()); |
| elements.add(IssuedToItem); |
| |
| X509CertificateAttribute sigAlgoItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_SIG_ALGO, theCert.getSigAlgName()); |
| elements.add(sigAlgoItem); |
| |
| boolean keyUsagesArray[] = theCert.getKeyUsage(); |
| StringBuilder keyUsages = new StringBuilder(); |
| // |
| // Only set the string field, If we got some data |
| if (keyUsagesArray != null && keyUsagesArray.length > 0) { |
| for (int i = 0; i < keyUsagesArray.length; i++) { |
| if (keyUsagesArray[i]) |
| keyUsages.append(keyUsageStrings[i] + listDelim); |
| } |
| |
| X509CertificateAttribute keyUsage = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_KEY_USAGE, (keyUsages.toString()).substring(0, keyUsages.length() - 2), theCert.getKeyUsage()); |
| elements.add(keyUsage); |
| } |
| |
| /* |
| * Thumbprint is not actually "in" the certificate. It is computed on the fly... |
| */ |
| X509CertificateAttribute thumbPrintItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_THMBPRINT, getThumbprint(theCert, "SHA1")); //$NON-NLS-1$ |
| elements.add(thumbPrintItem); |
| |
| PublicKey pubKey = theCert.getPublicKey(); |
| X509CertificateAttribute pubKeyInfoItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_THMBPRINTX509_PUBKEY_INFO, getHex(pubKey.getEncoded())); |
| elements.add(pubKeyInfoItem); |
| |
| try { |
| Collection<List<?>> subAltNamesVctr = theCert.getSubjectAlternativeNames(); |
| |
| // StringBuffer bfrSubAltNames = new StringBuffer(); |
| if (subAltNamesVctr != null && subAltNamesVctr.size() > 0) { |
| // TODO - Make alt names into a displayable list... |
| |
| // For now just display that they exist.. |
| X509CertificateAttribute subAltItem = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_SUB_ALT_NAMES, "Has Subject Alternate Names" /*bfrSubAltNames.toString()*/, theCert.getSubjectAlternativeNames()); //$NON-NLS-1$ |
| elements.add(subAltItem); |
| } |
| } catch (CertificateParsingException e1) { |
| // TODO Auto-generated catch block |
| e1.printStackTrace(); |
| } |
| int basicCnstrnts = theCert.getBasicConstraints(); |
| Integer basicConstraint = Integer.valueOf(basicCnstrnts); |
| StringBuilder basicCnstrntsBfr = new StringBuilder(); |
| if (basicCnstrnts == -1) { |
| // Not a CA |
| basicCnstrntsBfr.append(SecurityUIMsg.LABEL_NAMECONSTRAINTS_NOTCA + listDelim); |
| } else { |
| basicCnstrntsBfr.append(SecurityUIMsg.LABEL_NAMECONSTRAINTS_ISCA + listDelim); |
| if (basicCnstrnts == Integer.MAX_VALUE) { |
| // MAX_VALUE means "no limit to the allowed length of the certification path." |
| basicCnstrntsBfr.append(NLS.bind(SecurityUIMsg.LABEL_NAMECONSTRAINTS_PATHLENGTH, new Object[] {SecurityUIMsg.LABEL_NAMECONSTRAINTS_PATHLENGTH_UNLIMITED}) + listDelim); |
| } else { |
| basicCnstrntsBfr.append(NLS.bind(SecurityUIMsg.LABEL_NAMECONSTRAINTS_PATHLENGTH, new Object[] {basicConstraint}) + listDelim); |
| } |
| } |
| |
| X509CertificateAttribute basicConstraints = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_BASIC_CNSTRNTS, (basicCnstrntsBfr.toString()).substring(0, basicCnstrntsBfr.length() - 2), basicConstraint); |
| elements.add(basicConstraints); |
| |
| List<String> exKeyUsg; |
| try { |
| exKeyUsg = theCert.getExtendedKeyUsage(); |
| StringBuilder exKeyUsgBfr = new StringBuilder(); |
| if (exKeyUsg != null && exKeyUsg.size() > 0) { |
| for (String string : exKeyUsg) { |
| exKeyUsgBfr.append((string) + listDelim); |
| } |
| |
| X509CertificateAttribute exKeyUsgProp = new X509CertificateAttribute(SecurityUIMsg.CERTPROP_X509_EXKEY_USAGE, (exKeyUsgBfr.toString()).substring(0, exKeyUsgBfr.length() - 2), theCert.getExtendedKeyUsage()); |
| elements.add(exKeyUsgProp); |
| } |
| |
| } catch (CertificateParsingException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| |
| } |
| |
| } |
| |
| private String getHex(byte buf[]) { |
| String result = ""; //$NON-NLS-1$ |
| if (buf != null) { |
| for (int i = 0; i < buf.length; i++) { |
| if (i > 0) |
| result += " "; //$NON-NLS-1$ |
| |
| short sValue = buf[i]; |
| int curInt = 0; |
| curInt += sValue; |
| String converted = Integer.toHexString(curInt); |
| |
| if (converted.length() > 2) |
| converted = converted.substring(converted.length() - 2); |
| |
| result += converted.toUpperCase(); |
| } |
| } |
| return result; |
| } |
| |
| private MessageDigest getDigest(String thumAlg) { |
| MessageDigest md = null; |
| try { |
| md = MessageDigest.getInstance(thumAlg); |
| } catch (Exception e) { |
| // TODO - Handle the exception or log it.. |
| } |
| return md; |
| } |
| |
| private String getThumbprint(X509Certificate curCert, String thumAlg) { |
| String thumbPrint = ""; //$NON-NLS-1$ |
| try { |
| |
| MessageDigest md = getDigest(thumAlg); |
| md.update(curCert.getEncoded()); |
| byte rawDigest[] = md.digest(); |
| thumbPrint = getHex(rawDigest); |
| } catch (Exception e) { |
| // Might if thumb print algorithm can not be loaded. |
| |
| } |
| return thumbPrint; |
| } |
| |
| } |