summaryrefslogtreecommitdiffstats
path: root/pki/base/util/src/netscape/security/pkcs/SignerInfo.java
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/util/src/netscape/security/pkcs/SignerInfo.java')
-rw-r--r--pki/base/util/src/netscape/security/pkcs/SignerInfo.java344
1 files changed, 344 insertions, 0 deletions
diff --git a/pki/base/util/src/netscape/security/pkcs/SignerInfo.java b/pki/base/util/src/netscape/security/pkcs/SignerInfo.java
new file mode 100644
index 000000000..e03c32190
--- /dev/null
+++ b/pki/base/util/src/netscape/security/pkcs/SignerInfo.java
@@ -0,0 +1,344 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package netscape.security.pkcs;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.security.*;
+
+import netscape.security.util.*;
+import netscape.security.x509.AlgorithmId;
+import netscape.security.x509.X500Name;
+
+/**
+ * A SignerInfo, as defined in PKCS#7's signedData type.
+ *
+ * @author Benjamin Renaud
+ * @version 1.27 97/12/10
+ */
+public class SignerInfo implements DerEncoder {
+
+ BigInt version;
+ X500Name issuerName;
+ BigInt certificateSerialNumber;
+ AlgorithmId digestAlgorithmId;
+ AlgorithmId digestEncryptionAlgorithmId;
+ byte[] encryptedDigest;
+
+ PKCS9Attributes authenticatedAttributes;
+ PKCS9Attributes unauthenticatedAttributes;
+
+ public SignerInfo(X500Name issuerName,
+ BigInt serial,
+ AlgorithmId digestAlgorithmId,
+ AlgorithmId digestEncryptionAlgorithmId,
+ byte[] encryptedDigest) {
+ this.version = new BigInt(1);
+ this.issuerName = issuerName;
+ this.certificateSerialNumber = serial;
+ this.digestAlgorithmId = digestAlgorithmId;
+ this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
+ this.encryptedDigest = encryptedDigest;
+ }
+
+ public SignerInfo(X500Name issuerName,
+ BigInt serial,
+ AlgorithmId digestAlgorithmId,
+ PKCS9Attributes authenticatedAttributes,
+ AlgorithmId digestEncryptionAlgorithmId,
+ byte[] encryptedDigest,
+ PKCS9Attributes unauthenticatedAttributes) {
+ this.version = new BigInt(1);
+ this.issuerName = issuerName;
+ this.certificateSerialNumber = serial;
+ this.digestAlgorithmId = digestAlgorithmId;
+ this.authenticatedAttributes = authenticatedAttributes;
+ this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmId;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = unauthenticatedAttributes;
+ }
+
+ public SignerInfo(DerInputStream derin)
+ throws IOException, ParsingException {
+
+ // version
+ version = derin.getInteger();
+
+ // issuerAndSerialNumber
+ DerValue[] issuerAndSerialNumber = derin.getSequence(2);
+ byte[] issuerBytes = issuerAndSerialNumber[0].toByteArray();
+ issuerName = new X500Name(new DerValue(DerValue.tag_Sequence,
+ issuerBytes));
+ certificateSerialNumber = issuerAndSerialNumber[1].getInteger();
+
+ // digestAlgorithmId
+ DerValue tmp = derin.getDerValue();
+
+ digestAlgorithmId = AlgorithmId.parse(tmp);
+
+ /*
+ * check if set of auth attributes (implicit tag) is provided
+ * (auth attributes are OPTIONAL)
+ */
+ if ((byte)(derin.peekByte()) == (byte)0xA0) {
+ authenticatedAttributes = new PKCS9Attributes(derin);
+ }
+
+ // digestEncryptionAlgorithmId - little RSA naming scheme -
+ // signature == encryption...
+ tmp = derin.getDerValue();
+
+ digestEncryptionAlgorithmId = AlgorithmId.parse(tmp);
+
+ // encryptedDigest
+ encryptedDigest = derin.getOctetString();
+
+ /*
+ * check if set of unauth attributes (implicit tag) is provided
+ * (unauth attributes are OPTIONAL)
+ */
+ if (derin.available() != 0 && (byte)(derin.peekByte()) == (byte)0xA1) {
+ unauthenticatedAttributes = new PKCS9Attributes(derin);
+ }
+
+ // all done
+ if (derin.available() != 0) {
+ throw new ParsingException("extra data at the end");
+ }
+ }
+
+ public void encode(DerOutputStream out) throws IOException {
+
+ derEncode(out);
+ }
+
+ /**
+ * DER encode this object onto an output stream.
+ * Implements the <code>DerEncoder</code> interface.
+ *
+ * @param out
+ * the output stream on which to write the DER encoding.
+ *
+ * @exception IOException on encoding error.
+ */
+ public void derEncode(OutputStream out) throws IOException {
+ DerOutputStream seq = new DerOutputStream();
+ seq.putInteger(version);
+ DerOutputStream issuerAndSerialNumber = new DerOutputStream();
+ issuerName.encode(issuerAndSerialNumber);
+ issuerAndSerialNumber.putInteger(certificateSerialNumber);
+ seq.write(DerValue.tag_Sequence, issuerAndSerialNumber);
+
+ digestAlgorithmId.encode(seq);
+
+ // encode authenticated attributes if there are any
+ if (authenticatedAttributes != null)
+ authenticatedAttributes.encode((byte)0xA0, seq);
+
+ digestEncryptionAlgorithmId.encode(seq);
+
+ seq.putOctetString(encryptedDigest);
+
+ // encode unauthenticated attributes if there are any
+ if (unauthenticatedAttributes != null)
+ unauthenticatedAttributes.encode((byte)0xA1, seq);
+
+ DerOutputStream tmp = new DerOutputStream();
+ tmp.write(DerValue.tag_Sequence, seq);
+
+ out.write(tmp.toByteArray());
+ }
+
+
+
+ public X509Certificate getCertificate(PKCS7 block)
+ throws IOException {
+ return block.getCertificate(certificateSerialNumber, issuerName);
+ }
+
+ /* Returns null if verify fails, this signerInfo if
+ verify succeeds. */
+ SignerInfo verify(PKCS7 block, byte[] data)
+ throws NoSuchAlgorithmException, SignatureException {
+
+ try {
+
+ ContentInfo content = block.getContentInfo();
+ if (data == null) {
+ data = content.getContentBytes();
+ }
+
+ String digestAlgname =
+ getDigestAlgorithmId().getName();
+
+ byte[] dataSigned;
+
+ // if there are authenticate attributes, get the message
+ // digest and compare it with the digest of data
+ if (authenticatedAttributes == null) {
+ dataSigned = data;
+ } else {
+
+ // first, check content type
+ ObjectIdentifier contentType = (ObjectIdentifier)
+ authenticatedAttributes.getAttributeValue(
+ PKCS9Attribute.CONTENT_TYPE_OID);
+ if (contentType == null ||
+ !contentType.equals(content.contentType))
+ return null; // contentType does not match, bad SignerInfo
+
+ // now, check message digest
+ byte[] messageDigest = (byte[])
+ authenticatedAttributes.getAttributeValue(
+ PKCS9Attribute.MESSAGE_DIGEST_OID);
+
+ if (messageDigest == null) // fail if there is no message digest
+ return null;
+
+ MessageDigest md = MessageDigest.getInstance(digestAlgname);
+ byte[] computedMessageDigest = md.digest(data);
+
+ if (messageDigest.length != computedMessageDigest.length)
+ return null;
+ for (int i = 0; i < messageDigest.length; i++) {
+ if (messageDigest[i] != computedMessageDigest[i])
+ return null;
+ }
+
+ // message digest attribute matched
+ // digest of original data
+
+ // the data actually signed is the DER encoding of
+ // the authenticated attributes (tagged with
+ // the "SET OF" tag, not 0xA0).
+ dataSigned = authenticatedAttributes.getDerEncoding();
+ }
+
+ // put together digest algorithm and encryption algorithm
+ // to form signing algorithm
+ String encryptionAlgname =
+ getDigestEncryptionAlgorithmId().getName();
+
+ String algname;
+ if (encryptionAlgname.equals("DSA") ||
+ encryptionAlgname.equals("SHA1withDSA")) {
+ algname = "DSA";
+ } else {
+ algname = digestAlgname + "/" + encryptionAlgname;
+ }
+
+ Signature sig = Signature.getInstance(algname);
+ X509Certificate cert = getCertificate(block);
+
+ if (cert == null) {
+ return null;
+ }
+
+ PublicKey key = cert.getPublicKey();
+ sig.initVerify(key);
+
+ sig.update(dataSigned);
+
+ if (sig.verify(encryptedDigest)) {
+ return this;
+ }
+
+ } catch (IOException e) {
+ throw new SignatureException("IO error verifying signature:\n" +
+ e.getMessage());
+
+ } catch (InvalidKeyException e) {
+ throw new SignatureException("InvalidKey: " + e.getMessage());
+
+ }
+ return null;
+ }
+
+ /* Verify the content of the pkcs7 block. */
+ SignerInfo verify(PKCS7 block)
+ throws NoSuchAlgorithmException, SignatureException {
+ return verify(block, null);
+ }
+
+
+ public BigInt getVersion() {
+ return version;
+ }
+
+ public X500Name getIssuerName() {
+ return issuerName;
+ }
+
+ public BigInt getCertificateSerialNumber() {
+ return certificateSerialNumber;
+ }
+
+ public AlgorithmId getDigestAlgorithmId() {
+ return digestAlgorithmId;
+ }
+
+ public PKCS9Attributes getAuthenticatedAttributes() {
+ return authenticatedAttributes;
+ }
+
+ public AlgorithmId getDigestEncryptionAlgorithmId() {
+ return digestEncryptionAlgorithmId;
+ }
+
+ public byte[] getEncryptedDigest() {
+ return encryptedDigest;
+ }
+
+ public PKCS9Attributes getUnauthenticatedAttributes() {
+ return unauthenticatedAttributes;
+ }
+
+ public String toString() {
+ netscape.security.util.PrettyPrintFormat pp =
+ new netscape.security.util.PrettyPrintFormat(" ", 20);
+ String digestbits = pp.toHexString(encryptedDigest);
+
+ String out = "";
+
+ out += "Signer Info for (issuer): " + issuerName + "\n";
+ out += "\tversion: " + version + "\n";
+ out += "\tcertificateSerialNumber: " + certificateSerialNumber +
+ "\n";
+ out += "\tdigestAlgorithmId: " + digestAlgorithmId + "\n";
+ if (authenticatedAttributes != null) {
+ out += "\tauthenticatedAttributes: " + authenticatedAttributes +
+ "\n";
+ }
+ out += "\tdigestEncryptionAlgorithmId: " + digestEncryptionAlgorithmId +
+ "\n";
+
+ out += "\tencryptedDigest: " + "\n" +
+ digestbits + "\n";
+ if (unauthenticatedAttributes != null) {
+ out += "\tunauthenticatedAttributes: " +
+ unauthenticatedAttributes + "\n";
+ }
+ return out;
+ }
+
+}
+
+
+
+