/*
* 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 org.apache.harmony.security.pkcs7;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import javax.security.auth.x500.X500Principal;
import org.apache.harmony.security.asn1.ASN1Implicit;
import org.apache.harmony.security.asn1.ASN1Integer;
import org.apache.harmony.security.asn1.ASN1OctetString;
import org.apache.harmony.security.asn1.ASN1Sequence;
import org.apache.harmony.security.asn1.ASN1SetOf;
import org.apache.harmony.security.asn1.ASN1Type;
import org.apache.harmony.security.asn1.BerInputStream;
import org.apache.harmony.security.x501.AttributeTypeAndValue;
import org.apache.harmony.security.x501.Name;
import org.apache.harmony.security.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 getDigestAlgorithmName() {
return digestAlgorithm.getAlgorithmName();
}
public String getDigestEncryptionAlgorithm() {
return digestEncryptionAlgorithm.getAlgorithm();
}
public String getDigestEncryptionAlgorithmName() {
return digestEncryptionAlgorithm.getAlgorithmName();
}
public List<AttributeTypeAndValue> getAuthenticatedAttributes() {
if (authenticatedAttributes == null) {
return null;
}
return authenticatedAttributes.getAttributes();
}
/**
* Returns the non-IMPLICIT ASN.1 encoding of the "authAttrs" from this
* SignerInfo. That is, it will return as the encoding of a generic ASN.1
* SET.
*/
public byte[] getEncodedAuthenticatedAttributes() {
if (authenticatedAttributes == null) {
return null;
}
return AuthenticatedAttributes.ASN1.encode(authenticatedAttributes.getAttributes());
}
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]
);
}
};
}