Package codec.pkcs7

Source Code of codec.pkcs7.SignerInfo

/* ========================================================================
*
*  This file is part of CODEC, which is a Java package for encoding
*  and decoding ASN.1 data structures.
*
*  Author: Fraunhofer Institute for Computer Graphics Research IGD
*          Department A8: Security Technology
*          Fraunhoferstr. 5, 64283 Darmstadt, Germany
*
*  Rights: Copyright (c) 2004 by Fraunhofer-Gesellschaft
*          zur Foerderung der angewandten Forschung e.V.
*          Hansastr. 27c, 80686 Munich, Germany.
*
* ------------------------------------------------------------------------
*
*  The software package 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 2.1 of the
*  License, or (at your option) any later version.
*
*  This library 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 software package; if not, write to the Free
*  Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
*  MA 02110-1301, USA or obtain a copy of the license at
*  http://www.fsf.org/licensing/licenses/lgpl.txt.
*
* ------------------------------------------------------------------------
*
*  The CODEC library can solely be used and distributed according to
*  the terms and conditions of the GNU Lesser General Public License .
*
*  The CODEC library has not been tested for the use or application
*  for a determined purpose. It is a developing version that can
*  possibly contain errors. Therefore, Fraunhofer-Gesellschaft zur
*  Foerderung der angewandten Forschung e.V. does not warrant that the
*  operation of the CODEC library will be uninterrupted or error-free.
*  Neither does Fraunhofer-Gesellschaft zur Foerderung der angewandten
*  Forschung e.V. warrant that the CODEC library will operate and
*  interact in an uninterrupted or error-free way together with the
*  computer program libraries of third parties which the CODEC library
*  accesses and which are distributed together with the CODEC library.
*
*  Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
*  does not warrant that the operation of the third parties's computer
*  program libraries themselves which the CODEC library accesses will
*  be uninterrupted or error-free.
*
*  Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
*  shall not be liable for any errors or direct, indirect, special,
*  incidental or consequential damages, including lost profits resulting
*  from the combination of the CODEC library with software of any user
*  or of any third party or resulting from the implementation of the
*  CODEC library in any products, systems or services of any user or
*  of any third party.
*
*  Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V.
*  does not provide any warranty nor any liability that utilization of
*  the CODEC library will not interfere with third party intellectual
*  property rights or with any other protected third party rights or will
*  cause damage to third parties. Fraunhofer Gesellschaft zur Foerderung
*  der angewandten Forschung e.V. is currently not aware of any such
*  rights.
*
*  The CODEC library is supplied without any accompanying services.
*
* ========================================================================
*/
package codec.pkcs7;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;

import codec.InconsistentStateException;
import codec.asn1.ASN1Exception;
import codec.asn1.ASN1Integer;
import codec.asn1.ASN1Null;
import codec.asn1.ASN1ObjectIdentifier;
import codec.asn1.ASN1OctetString;
import codec.asn1.ASN1Sequence;
import codec.asn1.ASN1TaggedType;
import codec.asn1.ASN1Type;
import codec.asn1.DEREncoder;
import codec.asn1.Encoder;
import codec.asn1.OIDRegistry;
import codec.pkcs9.Attributes;
import codec.util.JCA;
import codec.x501.Attribute;
import codec.x501.BadNameException;
import codec.x501.Name;
import codec.x509.AlgorithmIdentifier;
import codec.x509.SubjectPublicKeyInfo;

/**
* ATTENTION : if this object shall use the strict DER encoding rules, the
* function setStrict(true) must be called right after instantiating the object.
*
* This class represents a PKCS#7 SignerInfo structure. It is defined as
* follows:
*
* <pre>
* SignerInfo ::= SEQUENCE {
*   version Version,
*   issuerAndSerialNumber IssuerAndSerialNumber,
*   digestAlgorithm DigestAlgorithmIdentifier,
*   authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
*   digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
*   encryptedDigest EncryptedDigest,
*   unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
* }
* EncryptedDigest ::= OCTET STRING
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
* DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
* </pre>
*
* For completeness, we also present the structures referenced in the SignerInfo
* structure.
*
* <pre>
* IssuerAndSerialNumber ::= SEQUENCE {
*   issuer Name,
*   serialNumber CertificateSerialNumber
* }
* CertificateSerialNumber ::= INTEGER
* Attributes ::= SET OF Attribute -- from X.501
* </pre>
*
* @author Volker Roth
* @version "$Id: SignerInfo.java,v 1.3 2004/08/12 12:31:42 pebinger Exp $"
*/
public class SignerInfo extends ASN1Sequence {
    /**
     * The version number of this SignerInfo.
     */
    protected ASN1Integer version_;

    /**
     * The issuer name. Still of type ANY but being replaced by RDName soon.
     */
    protected Name issuer_;

    /**
     * The serial number.
     */
    protected ASN1Integer serial_;

    /**
     * The {@link AlgorithmIdentifier DigestAlgorithmIdentifier}.
     */
    protected AlgorithmIdentifier dAlg_;

    /**
     * The {@link AlgorithmIdentifier DigestEncryptionAlgorithmIdentifier}.
     */
    protected AlgorithmIdentifier cAlg_;

    /**
     * The authenticated attributes.
     */
    protected Attributes auth_;

    /**
     * The unauthenticated attributes.
     */
    protected Attributes attr_;

    /**
     * The encrypted digest.
     */
    protected ASN1OctetString edig_;

    /**
     * The algorithm to use when a {@link SignedData SignedData} instance is
     * used for signing or verifying.
     */
    protected String algorithm_;

    /**
     * The signature algorithm parameters spec to use when verifying or signing
     * {@link SignedData SignedData} instances.
     */
    protected AlgorithmParameterSpec spec_;

    /**
     * if true, the strict DER encoding is used.
     */
    private boolean strict = false;

    /**
     * Creates an instance ready for decoding.
     */
    public SignerInfo() {
  super(7);

  ASN1Sequence seq;

  /* Global structure and Version */
  version_ = new ASN1Integer(1);
  add(version_);

  /* Issuer and serial number */
  issuer_ = new Name();
  serial_ = new ASN1Integer();

  seq = new ASN1Sequence(2);
  seq.add(issuer_);
  seq.add(serial_);

  add(seq);

  /* Digest Algorithm Identifier */
  dAlg_ = new AlgorithmIdentifier();
  add(dAlg_);

  /* Authenticated Attributes */
  auth_ = new Attributes();
  add(new ASN1TaggedType(0, auth_, false, true));

  /* Digest Encryption Algorithm Identifier */
  cAlg_ = new AlgorithmIdentifier();
  add(cAlg_);

  /* Encrypted Digest */
  edig_ = new ASN1OctetString();
  add(edig_);

  /* Unauthenticated Attributes */
  attr_ = new Attributes();
  add(new ASN1TaggedType(1, attr_, false, true));
    }

    /**
     * Creates an instance ready for decoding. The given registry is used to
     * resolve attributes.
     *
     * @param registry
     *                The <code>OIDRegistry</code> to use for resolving
     *                attributes, or <code>null</code> if the default PKCS
     *                registry shall be used.
     */
    public SignerInfo(OIDRegistry registry) {
  super(7);

  ASN1Sequence seq;

  /* Global structure and Version */
  version_ = new ASN1Integer(1);
  add(version_);

  /* Issuer and serial number */
  issuer_ = new Name();
  serial_ = new ASN1Integer();

  seq = new ASN1Sequence(2);
  seq.add(issuer_);
  seq.add(serial_);

  add(seq);

  /* Digest Algorithm Identifier */
  dAlg_ = new AlgorithmIdentifier();
  add(dAlg_);

  /* Authenticated Attributes */
  auth_ = new Attributes(registry);
  add(new ASN1TaggedType(0, auth_, false, true));

  /* Digest Encryption Algorithm Identifier */
  cAlg_ = new AlgorithmIdentifier();
  add(cAlg_);

  /* Encrypted Digest */
  edig_ = new ASN1OctetString();
  add(edig_);

  /* Unauthenticated Attributes */
  attr_ = new Attributes(registry);
  add(new ASN1TaggedType(1, attr_, false, true));
    }

    /**
     * This method calls initializes this structure with the given arguments.
     * This constructore creates Version 1 SignerInfos. The given algorithm must
     * be a PKCS#1 Version 1.5 conformant signature algorithm. In other words,
     * the signature algorithm MUST NOT have algorithm parameters beyond those
     * embedded in the {@link SubjectPublicKeyInfo SubjectPublicKeyInfo} of the
     * public key, and aliases for a slashed name form MUST be defined by JSPs
     * (Java Security Providers). JSPs also MUST define OID aliases for the
     * signature's raw cipher and the message digest.
     * <p>
     *
     * If PKCS#1 version 2.1 Draft 1 signatures (RSASSA-PSS) shall be used then
     * the constructor taking algorithm parameters must be called instead of
     * this one.
     *
     * @param cert
     *                The signer's certificate.
     * @param algorithm
     *                The JCA standard name of the PKCS#1 version 1.5 compliant
     *                signature algorithm.
     * @throws NoSuchAlgorithmException
     *                 if the signature algorithm name cannot be resolved to the
     *                 OIDs of the names of its raw cipher algorithm and its
     *                 digest algorithm.
     * @throws BadNameException
     *                 if the issuer name in the given certificate cannot be
     *                 parsed.
     * @throws IllegalArgumentException
     *                 if the OID to which the given algorithm name is mapped by
     *                 means of the aliases of the installed providers is not a
     *                 valid OID string.
     */
    public SignerInfo(X509Certificate cert, String algorithm)
      throws BadNameException, NoSuchAlgorithmException {
  super(7);

  ASN1Sequence seq;
  String d;
  String c;

  /* Global structure and Version */
  version_ = new ASN1Integer(1);
  add(version_);

  /* Issuer and serial number */
  issuer_ = new Name(cert.getIssuerDN().getName(), -1);
  serial_ = new ASN1Integer(cert.getSerialNumber());

  seq = new ASN1Sequence(2);
  seq.add(issuer_);
  seq.add(serial_);

  add(seq);

  /*
   * We now initialize the algorithm identifiers. The style is according
   * to PKCS#1 Version 1.5, no parameters for the signature algorithm.
   * Parameters are encoded as ASN1Null.
   */
  d = JCA.getDigestOID(algorithm);
  c = JCA.getCipherOID(algorithm);
  if (d == null || c == null) {
      throw new NoSuchAlgorithmException(
        "Cannot resolve signature algorithm!");
  }
  try {
      dAlg_ = new AlgorithmIdentifier(new ASN1ObjectIdentifier(d),
        new ASN1Null());
      cAlg_ = new AlgorithmIdentifier(new ASN1ObjectIdentifier(c),
        new ASN1Null());
  } catch (ASN1Exception e) {
      throw new InconsistentStateException(e);
  }
  /* Digest Algorithm Identifier */
  add(dAlg_);

  /* Authenticated Attributes */
  auth_ = new Attributes();
  add(new ASN1TaggedType(0, auth_, false, true));

  /* Digest Encryption Algorithm Identifier */
  add(cAlg_);

  /* Encrypted Digest */
  edig_ = new ASN1OctetString();
  add(edig_);

  /* Unauthenticated Attributes */
  attr_ = new Attributes();
  add(new ASN1TaggedType(1, attr_, false, true));

  algorithm_ = algorithm;
    }

    /**
     * method as above, but with an explicit encoding type
     *
     * @param cert
     * @param algorithm
     * @param nameEncoding
     * @throws BadNameException
     * @throws NoSuchAlgorithmException
     */

    public SignerInfo(X509Certificate cert, String algorithm, int nameEncoding)
      throws BadNameException, NoSuchAlgorithmException {
  super(7);

  ASN1Sequence seq;
  String d;
  String c;

  /* Global structure and Version */
  version_ = new ASN1Integer(1);
  add(version_);

  /* Issuer and serial number */
  // System.out.println("Choosen Printable");
  issuer_ = new Name(cert.getIssuerDN().getName(), nameEncoding);
  serial_ = new ASN1Integer(cert.getSerialNumber());

  seq = new ASN1Sequence(2);
  seq.add(issuer_);
  seq.add(serial_);

  add(seq);

  /*
   * We now initialize the algorithm identifiers. The style is according
   * to PKCS#1 Version 1.5, no parameters for the signature algorithm.
   * Parameters are encoded as ASN1Null.
   */
  d = JCA.getDigestOID(algorithm);
  c = JCA.getCipherOID(algorithm);
  if (d == null || c == null) {
      throw new NoSuchAlgorithmException(
        "Cannot resolve signature algorithm!");
  }
  try {
      dAlg_ = new AlgorithmIdentifier(new ASN1ObjectIdentifier(d),
        new ASN1Null());
      cAlg_ = new AlgorithmIdentifier(new ASN1ObjectIdentifier(c),
        new ASN1Null());
  } catch (ASN1Exception e) {
      throw new InconsistentStateException(e);
  }
  /* Digest Algorithm Identifier */
  add(dAlg_);

  /* Authenticated Attributes */
  auth_ = new Attributes();
  add(new ASN1TaggedType(0, auth_, false, true));

  /* Digest Encryption Algorithm Identifier */
  add(cAlg_);

  /* Encrypted Digest */
  edig_ = new ASN1OctetString();
  add(edig_);

  /* Unauthenticated Attributes */
  attr_ = new Attributes();
  add(new ASN1TaggedType(1, attr_, false, true));

  algorithm_ = algorithm;
    }

    /**
     * This method calls initializes this structure with the given arguments.
     * This constructore creates Version 1 SignerInfos. The given algorithm must
     * be a PKCS#1 Version 2.1 Draft 1 conformant signature algorithm. The
     * signature algorithm identifier is put into the place of the digest
     * algorithm identifier. The given parameters are those of the signature
     * algorithm (e. g. RSASSA-PSS). If the parameters are <code>null</code>
     * then they are encoded as {@link ASN1Null ASN1Null}. The signature
     * algorithm identifier is also put into the place of the digest encryption
     * algorithm identifier (without parameters). PKCS#1 Version 2.1 Draft 1
     * does not specify how this case should be handled so we picked our choice.
     *
     * @param cert
     *                The signer's certificate.
     * @param algorithm
     *                The JCA standard name of the PKCS#1 Version 2.1 Draft 1
     *                compliant signature algorithm.
     * @throws NoSuchAlgorithmException
     *                 if the signature algorithm name cannot be resolved to the
     *                 OIDs of the names of its raw cipher algorithm and its
     *                 digest algorithm.
     * @throws BadNameException
     *                 if the issuer name in the given certificate cannot be
     *                 parsed.
     */
    public SignerInfo(X509Certificate cert, String algorithm,
      AlgorithmParameters params) throws BadNameException,
      NoSuchAlgorithmException, InvalidAlgorithmParameterException {
  super(7);

  ASN1Sequence seq;
  String s;

  /* Global structure and Version */
  version_ = new ASN1Integer(1);
  add(version_);

  /* Issuer and serial number */
  issuer_ = new Name(cert.getIssuerDN().getName(), -1);
  serial_ = new ASN1Integer(cert.getSerialNumber());

  seq = new ASN1Sequence(2);
  seq.add(issuer_);
  seq.add(serial_);

  add(seq);

  /*
   * We now initialize the algorithm identifiers. The style is PKCS#1
   * Version 2.1 Draft 1 with the signature algorithm identifier in the
   * place of the digest algorithm identifier.
   */
  s = JCA.getOID(algorithm);
  if (s == null) {
      throw new NoSuchAlgorithmException(
        "Cannot resolve signature algorithm!");
  }
  dAlg_ = new AlgorithmIdentifier(s, params);
  cAlg_ = new AlgorithmIdentifier(s);

  /* Digest Algorithm Identifier */
  add(dAlg_);

  /* Authenticated Attributes */
  auth_ = new Attributes();
  add(new ASN1TaggedType(0, auth_, false, true));

  /* Digest Encryption Algorithm Identifier */
  add(cAlg_);

  /* Encrypted Digest */
  edig_ = new ASN1OctetString();
  add(edig_);

  /* Unauthenticated Attributes */
  attr_ = new Attributes();
  add(new ASN1TaggedType(1, attr_, false, true));

  algorithm_ = algorithm;
  if (params != null) {
      try {
    spec_ = params.getParameterSpec(AlgorithmParameterSpec.class);
      } catch (InvalidParameterSpecException e) {
    throw new InvalidAlgorithmParameterException(
      "Cannot transform params to spec!");
      }
  }
    }

    /**
     * same as above but with an explicit nameEncoding.
     *
     * @param cert
     * @param algorithm
     * @param params
     * @param nameEncoding
     * @throws BadNameException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     */
    public SignerInfo(X509Certificate cert, String algorithm,
      AlgorithmParameters params, int nameEncoding)
      throws BadNameException, NoSuchAlgorithmException,
      InvalidAlgorithmParameterException {
  super(7);

  ASN1Sequence seq;
  String s;

  /* Global structure and Version */
  version_ = new ASN1Integer(1);
  add(version_);

  /* Issuer and serial number */
  issuer_ = new Name(cert.getIssuerDN().getName(), nameEncoding);
  serial_ = new ASN1Integer(cert.getSerialNumber());

  seq = new ASN1Sequence(2);
  seq.add(issuer_);
  seq.add(serial_);

  add(seq);

  /*
   * We now initialize the algorithm identifiers. The style is PKCS#1
   * Version 2.1 Draft 1 with the signature algorithm identifier in the
   * place of the digest algorithm identifier.
   */
  s = JCA.getOID(algorithm);
  if (s == null) {
      throw new NoSuchAlgorithmException(
        "Cannot resolve signature algorithm!");
  }
  dAlg_ = new AlgorithmIdentifier(s, params);
  cAlg_ = new AlgorithmIdentifier(s);

  /* Digest Algorithm Identifier */
  add(dAlg_);

  /* Authenticated Attributes */
  auth_ = new Attributes();
  add(new ASN1TaggedType(0, auth_, false, true));

  /* Digest Encryption Algorithm Identifier */
  add(cAlg_);

  /* Encrypted Digest */
  edig_ = new ASN1OctetString();
  add(edig_);

  /* Unauthenticated Attributes */
  attr_ = new Attributes();
  add(new ASN1TaggedType(1, attr_, false, true));

  algorithm_ = algorithm;
  if (params != null) {
      try {
    spec_ = params.getParameterSpec(AlgorithmParameterSpec.class);
      } catch (InvalidParameterSpecException e) {
    throw new InvalidAlgorithmParameterException(
      "Cannot transform params to spec!");
      }
  }
    }

    /**
     * sets the strict parameter with the given value.
     */
    public void setStrict(boolean strictness) {
  this.strict = strictness;
    }

    /**
     * This method updates the given Signature instance with the DER encoding of
     * the <code>authenticatedAttributes
     * </code> file of the SignerInfo
     * structure if such attributes are given.
     *
     * @param sig
     *                The Signature instance to be updated.
     * @throws SignatureException
     *                 if the signature instance is not properly initialized.
     * @throws InconsistentStateException
     *                 in case of an internal error -- this should never happen.
     */
    public void update(Signature sig) throws SignatureException {
  if (sig == null)
      throw new NullPointerException("Sig is null!");

  if (auth_.size() > 0) {
      ByteArrayOutputStream bos;
      DEREncoder enc;

      try {
    bos = new ByteArrayOutputStream();
    enc = new DEREncoder(bos);
    if (this.strict)
        enc.setStrict(true);

    /*
     * Because the authenticated attributes are tagged IMPLICIT in
     * version 1.5 we have to set tagging to EXPLICIT during
     * encoding. Otherwise the identifier and length octets would be
     * missing in the encoding.
     */
    auth_.setExplicit(true);
    auth_.encode(enc);

    sig.update(bos.toByteArray());

    enc.close();
      } catch (ASN1Exception e) {
    throw new InconsistentStateException(e);
      } catch (IOException e) {
    throw new InconsistentStateException(e);
      } finally {
    /*
     * No matter what happens, in order to maintain the consistency
     * of the internal structure we have to set the tagging of the
     * authenticated attributes back to IMPLICIT.
     */
    auth_.setExplicit(false);
      }
  }
    }

    /**
     * This method sets the encrypted digest.
     *
     * @param edig
     *                The encrypted digest.
     */
    public void setEncryptedDigest(byte[] edig) {
  edig_ = new ASN1OctetString(edig);
  set(5, edig_);
    }

    /**
     * This method returns the encrypted digest stored in this structure. The
     * EncryptedDigest is defined as
     *
     * <pre>
     * EncryptedDigest ::= OCTET STRING
     * </pre>
     *
     * This octet string contains the encrypted digest info structure, which is
     * reproduced below for completeness:
     *
     * <pre>
     * DigestInfo ::= SEQUENCE {
     *   digestAlgorithm DigestAlgorithmIdentifier,
     *   digest Digest
     * }
     * Digest ::= OCTET STRING
     * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
     * </pre>
     *
     * @return The encrypted digest.
     */
    public byte[] getEncryptedDigest() {
  return edig_.getByteArray();
    }

    /**
     * Returns the authenticated attributes.
     *
     * @return The unmodifiable list of authenticated attributes.
     */
    public Attributes authenticatedAttributes() {
  return auth_;
    }

    /**
     * Adds the given {@link Attribute attribute} to the list of authenticated
     * attributes. This method should be used to add attributes because it
     * clears the attributes instance's <code>OPTIONAL</code> flag.
     * Alternatively, this can be done manually.
     *
     * @param attr
     *                The attribute.
     */
    public void addAuthenticatedAttribute(Attribute attr) {
  if (attr == null)
      throw new NullPointerException("Need an attribute!");

  auth_.add(attr);
    }

    /**
     * Returns the unauthenticated attributes.
     *
     * @return The unmodifiable list of unauthenticated attributes.
     */
    public Attributes unauthenticatedAttributes() {
  return attr_;
    }

    /**
     * Adds the given {@link Attribute attribute} to the list of unauthenticated
     * attributes. This method should be used to add attributes because it
     * clears the attributes instance's <code>OPTIONAL</code> flag.
     * Alternatively, this can be done manually.
     *
     * @param attr
     *                The attribute.
     */
    public void addUnauthenticatedAttribute(Attribute attr) {
  if (attr == null)
      throw new NullPointerException("Need an attribute!");

  attr_.add(attr);
    }

    /**
     * Returns the {@link Name name} of the issuer of the certificate of this
     * signer.
     *
     * @return The issuer name.
     */
    public Principal getIssuerDN() {
  return issuer_;
    }

    /**
     *
     * @return The serial number.
     */
    public BigInteger getSerialNumber() {
  return serial_.getBigInteger();
    }

    /**
     * This method returns the DigestAlgorithmIdentifier.
     *
     * @return The DigestAlgorithmIdentifier.
     */
    public AlgorithmIdentifier getDigestAlgorithmIdentifier() {
  return dAlg_;
    }

    /**
     * Returns the name of the signature algorithm. This method calls
     * {@link #init init()} if the name is not yet known in order to determine
     * it by means of the {@link JCA JCA} and the
     * {@link AlgorithmIdentifier algorithm identifiers} embedded in this
     * structure.
     *
     * @return The algorithm name.
     * @throws NoSuchAlgorithmException
     *                 if the OIDs in this structure cannot be mapped onto an
     *                 algorithm name by means of the alias definitions of the
     *                 installed providers.
     * @throws InvalidAlgorithmParameterException
     *                 if the signature algorithm identifier contains parameters
     *                 but the parameters cannot be decoded.
     */
    public String getAlgorithm() throws NoSuchAlgorithmException,
      InvalidAlgorithmParameterException {
  if (algorithm_ == null)
      init();

  return algorithm_;
    }

    /**
     * Returns the algorithm parameter spec for the parameters of the signature
     * algorithm (PKCS#1 Version 2.1 Draft 1) or <code>null</code> if there
     * are none.
     *
     * @return The AlgorithmParameterSpec to use when initializing the signature
     *         engine.
     * @throws NoSuchAlgorithmException
     *                 if the OIDs in this structure cannot be mapped onto an
     *                 algorithm name by means of the alias definitions of the
     *                 installed providers.
     * @throws InvalidAlgorithmParameterException
     *                 if the signature algorithm identifier contains parameters
     *                 but the parameters cannot be decoded.
     */
    public AlgorithmParameterSpec getParameterSpec()
      throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
  if (spec_ == null)
      init();

  return spec_;
    }

    /**
     * This method determines the signature algorithm and appropriate parameters
     * for initializing the signature algorithm from the algorithm identifiers
     * in this structure. PKCS#1 versions 1.5 and 2.1 Draft 1 are supported.
     * <p>
     *
     * We start by resolving the digest and cipher OIDs against a signature
     * algorithm name by means of the {@link JCA JCA} class. This requires JSPs
     * (Java Security Providers) to support appropriate alias mappings. Both OID
     * mappings and slashed forms are required.
     * <p>
     *
     * If this fails then we try to interpret the digest algorithm identifier as
     * the signature algorithm identifier. If this still does not give us a
     * valid signature engine then we try the digest encryption algorithm
     * identifier as the signature algorithm identifier.
     * <p>
     *
     * If the combined form led to the signature engine then no parameters are
     * set (apart from those in the public key's
     * {@link SubjectPublicKeyInfo SubjectPublicKeyInfo}. If either the digest
     * algorithm identifier or the digest encryption algorithm identifier led to
     * the signature engine then the respective parameters are set for the
     * signature engine.
     * <p>
     *
     * Parameters are set before the signature engine is initialized with the
     * public key. No hint is given in the JDK documentation on which is to be
     * done first. So we picked our choice.
     * <p>
     *
     * Parameter initialization works only if the parameters engine supports
     * proper conversion of opaque parameter representations into transparent
     * representations (AlgorithmParameterSpecs) by means of the
     * <code>getAlgorithmParameterSpec()</code> method. Hardly any provider
     * gets it right, at the time of writing not even the Sun JSP does it
     * correctly.
     */
    protected void init() throws NoSuchAlgorithmException,
      InvalidAlgorithmParameterException {
  AlgorithmParameters params;
  String d;
  String c;
  String s;

  d = dAlg_.getAlgorithmOID().toString();
  c = cAlg_.getAlgorithmOID().toString();
  s = JCA.getSignatureName(d, c);

  if (s != null) {
      algorithm_ = s;
      return;
  }
  /*
   * If we cannot resolve the combined digest/cipher name to a signature
   * alg name then we try the digest algorithm identifier instead. This is
   * the recommended way as of PKCS#1 Version 2.1 Draft 1.
   */
  s = JCA.resolveAlias("Signature", d);

  if (s != null) {
      algorithm_ = s;
      params = dAlg_.getParameters();
  } else {
      /*
       * If we cannot get an instance by ordinary means then we try the
       * cipher algorithm identifier as a last resort. This is not
       * standard however.
       */
      s = JCA.resolveAlias("Signature", c);

      if (s != null) {
    algorithm_ = s;
    params = cAlg_.getParameters();
      } else {
    throw new NoSuchAlgorithmException("Cannot resolve OIDs!");
      }
  }
  try {
      spec_ = (params == null) ? null : params
        .getParameterSpec(AlgorithmParameterSpec.class);
  } catch (InvalidParameterSpecException e) {
      throw new InvalidAlgorithmParameterException(
        "Cannot convert params into spec!");
  }
    }

    /**
     * Checks if this <code>SignerInfo</code> has an issuer distinguished name
     * and a serial number that are equivalent to those in the given
     * certificate.
     *
     * @param cert
     *                The certificate to compare to.
     * @return <code>true</code> if this <code>SignerInfo
     *   </code> matches the
     *         given certificate.
     */
    public boolean equivIssuerAndSerialNumber(X509Certificate cert) {
  if (cert == null)
      throw new NullPointerException("Need a cert!");

  if (!issuer_.equals(cert.getIssuerDN()))
      return false;

  return serial_.getBigInteger().equals(cert.getSerialNumber());
    }

    /**
     * Returns a string representation of this object.
     *
     * @return The string representation.
     */
    public String toString() {
  StringBuffer buf;
  String alg;

  try {
      alg = getAlgorithm();
  } catch (Exception e) {
      alg = "<unknown>";
  }
  buf = new StringBuffer();
  buf.append("PKCS#7 SignerInfo {\n" + "Version   : "
    + version_.toString() + "\n" + "Issuer    : "
    + issuer_.getName() + "\n" + "Serial    : "
    + serial_.toString() + "\n" + "Algorithm : " + alg + "\n"
    + "Auth A    : " + auth_.size() + " elements\n"
    + "Unauth A  : " + attr_.size() + " elements\n"
    + "Signature : " + edig_.toString() + "\n");

  if (auth_.size() > 0) {
      buf.append("\n" + auth_);
  }
  buf.append("}\n");

  return buf.toString();
    }

    /**
     * Encodes this <code>SignerInfo</code>.
     *
     * @param encoder
     *                The encoder to use.
     */
    public void encode(Encoder encoder) throws IOException, ASN1Exception {
  /*
   * Yet another nail in my coffin...
   */
  ASN1Type t;
  boolean opt;

  t = (ASN1Type) get(3);
  opt = (auth_.size() == 0);
  t.setOptional(opt);

  t = (ASN1Type) get(6);
  opt = (attr_.size() == 0);
  t.setOptional(opt);

  super.encode(encoder);
    }

}
TOP

Related Classes of codec.pkcs7.SignerInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.