content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You 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.
   */
  
  /**
  * @author Boris Kuznetsov
  * @version $Revision$
  */
  package android.framework.org.apache.harmony.security_custom.pkcs7;
  
  import java.io.IOException;
  import java.math.BigInteger;
  import java.util.List;
  import javax.security.auth.x500.X500Principal;
  import android.framework.org.apache.harmony.security_custom.asn1.ASN1Implicit;
  import android.framework.org.apache.harmony.security_custom.asn1.ASN1Integer;
  import android.framework.org.apache.harmony.security_custom.asn1.ASN1OctetString;
  import android.framework.org.apache.harmony.security_custom.asn1.ASN1Sequence;
  import android.framework.org.apache.harmony.security_custom.asn1.ASN1SetOf;
  import android.framework.org.apache.harmony.security_custom.asn1.ASN1Type;
  import android.framework.org.apache.harmony.security_custom.asn1.BerInputStream;
  import android.framework.org.apache.harmony.security_custom.x501.AttributeTypeAndValue;
  import android.framework.org.apache.harmony.security_custom.x501.Name;
  import android.framework.org.apache.harmony.security_custom.x509.AlgorithmIdentifier;
  
  
  /**
   * As defined in PKCS #7: Cryptographic Message Syntax Standard
   * (http://www.ietf.org/rfc/rfc2315.txt)
   *
   * SignerInfo ::= SEQUENCE {
   *   version Version,
   *   issuerAndSerialNumber IssuerAndSerialNumber,
   *   digestAlgorithm DigestAlgorithmIdentifier,
   *   authenticatedAttributes
   *     [0] IMPLICIT Attributes OPTIONAL,
   *   digestEncryptionAlgorithm
   *     DigestEncryptionAlgorithmIdentifier,
   *   encryptedDigest EncryptedDigest,
   *   unauthenticatedAttributes
   *     [1] IMPLICIT Attributes OPTIONAL
   *  }
   */
  public final class SignerInfo {
      private final int version;
      private final X500Principal issuer;
      private final BigInteger serialNumber;
      private final AlgorithmIdentifier digestAlgorithm;
      private final AuthenticatedAttributes authenticatedAttributes;
      private final AlgorithmIdentifier digestEncryptionAlgorithm;
      private final byte[] encryptedDigest;
      private final List<?> unauthenticatedAttributes;
  
      private SignerInfo(int version,
              Object[] issuerAndSerialNumber,
              AlgorithmIdentifier digestAlgorithm,
              AuthenticatedAttributes authenticatedAttributes,
              AlgorithmIdentifier digestEncryptionAlgorithm,
              byte[] encryptedDigest,
              List<?> unauthenticatedAttributes) {
          this.version = version;
          this.issuer = ((Name)issuerAndSerialNumber[0]).getX500Principal();
          this.serialNumber = ASN1Integer.toBigIntegerValue(issuerAndSerialNumber[1]);
          this.digestAlgorithm = digestAlgorithm;
          this.authenticatedAttributes = authenticatedAttributes;
          this.digestEncryptionAlgorithm = digestEncryptionAlgorithm;
          this.encryptedDigest = encryptedDigest;
          this.unauthenticatedAttributes = unauthenticatedAttributes;
      }
  
      public X500Principal getIssuer() {
          return issuer;
      }
  
      public BigInteger getSerialNumber() {
          return serialNumber;
      }
  
      public String getDigestAlgorithm() {
          return digestAlgorithm.getAlgorithm();
      }
  
      public String getDigestEncryptionAlgorithm() {
          return digestEncryptionAlgorithm.getAlgorithm();
      }
  
      public List<AttributeTypeAndValue> getAuthenticatedAttributes() {
          if (authenticatedAttributes == null) {
              return null;
          }
          return authenticatedAttributes.getAttributes();
      }
  
      public byte[] getEncodedAuthenticatedAttributes() {
          if (authenticatedAttributes == null) {
              return null;
          }
          return authenticatedAttributes.getEncoded();
      }
  
      public byte[] getEncryptedDigest() {
          return encryptedDigest;
      }
  
  
      public String toString() {
          StringBuilder res = new StringBuilder();
          res.append("-- SignerInfo:");
          res.append("\n version : ");
          res.append(version);
          res.append("\nissuerAndSerialNumber:  ");
          res.append(issuer);
          res.append("   ");
          res.append(serialNumber);
          res.append("\ndigestAlgorithm:  ");
          res.append(digestAlgorithm.toString());
          res.append("\nauthenticatedAttributes:  ");
          if (authenticatedAttributes != null) {
              res.append(authenticatedAttributes.toString());
          }
          res.append("\ndigestEncryptionAlgorithm: ");
          res.append(digestEncryptionAlgorithm.toString());
          res.append("\nunauthenticatedAttributes: ");
          if (unauthenticatedAttributes != null) {
              res.append(unauthenticatedAttributes.toString());
          }
          res.append("\n-- SignerInfo End\n");
          return res.toString();
      }
  
  
      public static final ASN1Sequence ISSUER_AND_SERIAL_NUMBER =
              new ASN1Sequence(new ASN1Type[] {
                  Name.ASN1,                       // issuer
                  ASN1Integer.getInstance(),       // serialNumber
              })
          {
              // method to encode
              @Override public void getValues(Object object, Object[] values) {
                  Object [] issAndSerial = (Object[])object;
                  values[0] = issAndSerial[0];
                  values[1] = issAndSerial[1];
          }
      };
  
      public static final ASN1Sequence ASN1 =
          new ASN1Sequence(new ASN1Type[] {
                  ASN1Integer.getInstance(),         //version
                  ISSUER_AND_SERIAL_NUMBER,
                  AlgorithmIdentifier.ASN1,           //digestAlgorithm
                  new ASN1Implicit(0, AuthenticatedAttributes.ASN1),//authenticatedAttributes
                  AlgorithmIdentifier.ASN1,            //digestEncryptionAlgorithm
                  ASN1OctetString.getInstance(),       //encryptedDigest
                   new ASN1Implicit(1, new ASN1SetOf(
                           AttributeTypeAndValue.ASN1)),//unauthenticatedAttributes
                  })  {
          {
              setOptional(3); // authenticatedAttributes is optional
              setOptional(6); // unauthenticatedAttributes is optional
          }
  
          @Override protected void getValues(Object object, Object[] values) {
              SignerInfo si = (SignerInfo) object;
              values[0] = new byte[] {(byte)si.version};
              try {
                  values[1] = new Object[] { new Name(si.issuer.getName()),
                          si.serialNumber.toByteArray() };
              } catch (IOException e) {
                  // The exception is never thrown, because si.issuer
                  // is created using Name.getX500Principal().
                  // Throw a RuntimeException just to be safe.
                  throw new RuntimeException("Failed to encode issuer name", e);
              }
              values[2] = si.digestAlgorithm;
              values[3] = si.authenticatedAttributes;
              values[4] = si.digestEncryptionAlgorithm;
              values[5] = si.encryptedDigest;
              values[6] = si.unauthenticatedAttributes;
          }
  
          @Override protected Object getDecodedObject(BerInputStream in) {
              Object[] values = (Object[]) in.content;
              return new SignerInfo(
                          ASN1Integer.toIntValue(values[0]),
                          (Object[]) values[1],
                          (AlgorithmIdentifier) values[2],
                          (AuthenticatedAttributes) values[3],
                          (AlgorithmIdentifier) values[4],
                          (byte[]) values[5],
                          (List) values[6]
                      );
          }
     };
  }
  