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

net.named_data.jndn.security.certificate.Certificate Maven / Gradle / Ivy

Go to download

jNDN is a new implementation of a Named Data Networking client library written in Java. It is wire format compatible with the new NDN-TLV encoding, with NDNx and PARC's CCNx.

There is a newer version: 0.25
Show newest version
/**
 * Copyright (C) 2014-2017 Regents of the University of California.
 * @author: Jeff Thompson 
 * @author: From PyNDN certificate.py by Adeola Bannis .
 * @author: Originally from code in ndn-cxx by Yingdi Yu 
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 * A copy of the GNU Lesser General Public License is in the file COPYING.
 */

package net.named_data.jndn.security.certificate;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import net.named_data.jndn.ContentType;
import net.named_data.jndn.Data;
import net.named_data.jndn.Sha256WithRsaSignature;
import net.named_data.jndn.encoding.EncodingException;
import net.named_data.jndn.encoding.WireFormat;
import net.named_data.jndn.encoding.der.DerDecodingException;
import net.named_data.jndn.encoding.der.DerEncodingException;
import net.named_data.jndn.encoding.der.DerNode;
import net.named_data.jndn.encoding.der.DerNode.DerBoolean;
import net.named_data.jndn.encoding.der.DerNode.DerGeneralizedTime;
import net.named_data.jndn.encoding.der.DerNode.DerSequence;
import net.named_data.jndn.security.UnrecognizedKeyFormatException;
import net.named_data.jndn.util.Blob;
import net.named_data.jndn.util.Common;

public class Certificate extends Data {
  /**
   * The default constructor.
   */
  public Certificate()
  {
  }

  /**
   * Create a Certificate from the content in the data packet.
   * @param data The data packet with the content to decode.
   */
  public Certificate(Data data) throws DerDecodingException
  {
    super(data);
    decode();
  }

  /**
   * Encode the contents of the certificate in DER format and set the Content
   * and MetaInfo fields.
   */
  public final void
  encode() throws DerEncodingException, DerDecodingException
  {
    DerNode root = toDer();
    setContent(root.encode());
    getMetaInfo().setType(ContentType.KEY);
  }

  /**
   * Override to call the base class wireDecode then populate the certificate
   * fields.
   * @param input The input byte array to be decoded as an immutable Blob.
   * @param wireFormat A WireFormat object used to decode the input.
   */
  public void
  wireDecode(Blob input, WireFormat wireFormat)
    throws EncodingException
  {
    super.wireDecode(input, wireFormat);
    try {
      decode();
    } catch (DerDecodingException ex) {
      throw new EncodingException(ex.getMessage());
    }
  }

  /**
   * Add a subject description.
   * @param description The description to be added.
   */
  public final void
  addSubjectDescription(CertificateSubjectDescription description)
  {
    subjectDescriptionList_.add(description);
  }

  // List of CertificateSubjectDescription.
  public final List
  getSubjectDescriptionList()
  {
    return subjectDescriptionList_;
  }

  /**
   * Add a certificate extension.
   * @param extension the extension to be added
   */
  public final void
  addExtension(CertificateExtension extension)
  {
    extensionList_.add(extension);
  }

  // List of CertificateExtension.
  public final List
  getExtensionList()
  {
    return extensionList_;
  }

  public final void
  setNotBefore(double notBefore)
  {
    notBefore_ = notBefore;
  }

  public final double
  getNotBefore()
  {
    return notBefore_;
  }

  public final void
  setNotAfter(double notAfter)
  {
    notAfter_ = notAfter;
  }

  public final double
  getNotAfter()
  {
    return notAfter_;
  }

  public final void
  setPublicKeyInfo(PublicKey key)
  {
    key_ = key;
  }

  public final PublicKey
  getPublicKeyInfo()
  {
    return key_;
  }

  /**
   * Get the public key DER encoding.
   * @return The DER encoding Blob.
   * @throws Error if the public key is not set.
   */
  public final Blob
  getPublicKeyDer()
  {
    if (key_.getKeyDer().isNull())
      throw new Error("The public key is not set");

    return key_.getKeyDer();
  }

  /**
   * Check if the certificate is valid.
   * @return True if the current time is earlier than notBefore.
   */
  public final boolean
  isTooEarly()
  {
    double now = Common.getNowMilliseconds();
    return now < getNotBefore();
  }

  /**
   * Check if the certificate is valid.
   * @return True if the current time is later than notAfter.
   */
  public final boolean
  isTooLate()
  {
    double now = Common.getNowMilliseconds();
    return now > getNotAfter();
  }

  public final boolean
  isInValidityPeriod(double time)
  {
    // Debug: Generalize this from Sha256WithRsaSignature.
    return ((Sha256WithRsaSignature)getSignature()).getValidityPeriod().isValid
      (time);
  }

  /**
   * Encode the certificate fields in DER format.
   * @return The DER encoded contents of the certificate.
   */
  private DerSequence
  toDer() throws DerEncodingException, DerDecodingException
  {
    DerSequence root = new DerSequence();
    DerSequence validity = new DerSequence();
    DerGeneralizedTime notBefore = new DerGeneralizedTime(getNotBefore());
    DerGeneralizedTime notAfter = new DerGeneralizedTime(getNotAfter());

    validity.addChild(notBefore);
    validity.addChild(notAfter);

    root.addChild(validity);

    DerSequence subjectList = new DerSequence();
    for (int i = 0; i < subjectDescriptionList_.size(); ++i)
      subjectList.addChild(((CertificateSubjectDescription)subjectDescriptionList_.get(i)).toDer());

    root.addChild(subjectList);
    root.addChild(key_.toDer());

    if (extensionList_.size() > 0) {
      DerSequence extensionList = new DerSequence();
      for (int i = 0; i < extensionList_.size(); ++i)
        extensionList.addChild(((CertificateExtension)extensionList_.get(i)).toDer());
      root.addChild(extensionList);
    }

    return root;
  }

  /**
   * Populate the fields by the decoding DER data from the Content.
   */
  private void
  decode() throws DerDecodingException
  {
    DerNode parsedNode = DerNode.parse(getContent().buf());

    // We need to ensure that there are:
    //   validity (notBefore, notAfter)
    //   subject list
    //   public key
    //   (optional) extension list

    List rootChildren = parsedNode.getChildren();
    // 1st: validity info
    List validityChildren = DerNode.getSequence(rootChildren, 0).getChildren();
    notBefore_ = (Double)((DerGeneralizedTime)validityChildren.get(0)).toVal();
    notAfter_ = (Double)((DerGeneralizedTime)validityChildren.get(1)).toVal();

    // 2nd: subjectList
    List subjectChildren = DerNode.getSequence(rootChildren, 1).getChildren();
    for (int i = 0; i < subjectChildren.size(); ++i) {
      DerSequence sd = DerNode.getSequence(subjectChildren, i);
      List descriptionChildren = sd.getChildren();
      String oidStr = (String)((DerNode)descriptionChildren.get(0)).toVal();
      String value = "" + ((Blob)((DerNode)descriptionChildren.get(1)).toVal());

      addSubjectDescription(new CertificateSubjectDescription(oidStr, value));
    }

    // 3rd: public key
    Blob publicKeyInfo = ((DerNode)rootChildren.get(2)).encode();
    try {
      key_ = new PublicKey(publicKeyInfo);
    }
    catch (UnrecognizedKeyFormatException ex) {
      throw new DerDecodingException(ex.getMessage());
    }

    if (rootChildren.size() > 3) {
      List extensionChildren = DerNode.getSequence(rootChildren, 3).getChildren();
      for (int i = 0; i < extensionChildren.size(); ++i) {
        DerSequence extInfo = DerNode.getSequence(extensionChildren, i);

        List children = extInfo.getChildren();
        String oidStr = (String)((DerNode)children.get(0)).toVal();
        boolean isCritical = (Boolean)((DerBoolean)children.get(1)).toVal();
        Blob value = (Blob)((DerNode)children.get(2)).toVal();
        addExtension(new CertificateExtension(oidStr, isCritical, value));
      }
    }
  }

  public String
  toString()
  {
    String s = "Certificate name:\n";
    s += "  " + getName().toUri() + "\n";
    s += "Validity:\n";

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    String notBeforeStr = dateFormat.format
      (Common.millisecondsSince1970ToDate((long)Math.round(getNotBefore())));
    String notAfterStr = dateFormat.format
      (Common.millisecondsSince1970ToDate((long)Math.round(getNotAfter())));

    s += "  NotBefore: " + notBeforeStr + "\n";
    s += "  NotAfter: " + notAfterStr + "\n";
    for (int i = 0; i < subjectDescriptionList_.size(); ++i) {
      CertificateSubjectDescription sd =
        (CertificateSubjectDescription)subjectDescriptionList_.get(i);
      s += "Subject Description:\n";
      s += "  " + sd.getOidString() + ": " + sd.getValue() + "\n";
    }

    s += "Public key bits:\n";
    Blob keyDer = getPublicKeyDer();
    String encodedKey = Common.base64Encode(keyDer.getImmutableArray());
    for (int i = 0; i < encodedKey.length(); i += 64)
      s += encodedKey.substring(i, Math.min(i + 64, encodedKey.length())) + "\n";

    if (extensionList_.size() > 0) {
      s += "Extensions:\n";
      for (int i = 0; i < extensionList_.size(); ++i) {
        CertificateExtension ext = (CertificateExtension)extensionList_.get(i);
        s += "  OID: " + ext.getOid() + "\n";
        s += "  Is critical: " + (ext.getIsCritical() ? 'Y' : 'N') + "\n";

        s += "  Value: " + ext.getValue().toHex() + "\n" ;
      }
    }

    return s;
  }

  // Use ArrayList without generics so it works with older Java compilers.
  private final ArrayList subjectDescriptionList_ = new ArrayList(); // of CertificateSubjectDescription
  private final ArrayList extensionList_ = new ArrayList();          // of CertificateExtension
  private double notBefore_ = Double.MAX_VALUE; // MillisecondsSince1970
  private double notAfter_ = -Double.MAX_VALUE; // MillisecondsSince1970
  private PublicKey key_ = new PublicKey();
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy