blob: ef247d5906a022796162e017178afe85381d7d97 [file] [log] [blame]
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8048357
* @summary test PKCS7 data signing, encoding and verification
* @modules java.base/sun.security.pkcs
* java.base/sun.security.util
* java.base/sun.security.x509
* @run main SignerOrder
*/
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.X509Certificate;
import java.util.Date;
import sun.security.util.HexDumpEncoder;
import sun.security.pkcs.ContentInfo;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
import sun.security.util.DerOutputStream;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
import sun.security.x509.X509Key;
public class SignerOrder {
static final HexDumpEncoder hexDump = new HexDumpEncoder();
//signer infos
static final byte[] data1 = "12345".getBytes();
static final byte[] data2 = "abcde".getBytes();
public static void main(String[] argv) throws Exception {
SignerInfo[] signerInfos = new SignerInfo[9];
SimpleSigner signer1 = new SimpleSigner(null, null, null, null);
signerInfos[8] = signer1.genSignerInfo(data1);
signerInfos[7] = signer1.genSignerInfo(new byte[]{});
signerInfos[6] = signer1.genSignerInfo(data2);
SimpleSigner signer2 = new SimpleSigner(null, null, null, null);
signerInfos[5] = signer2.genSignerInfo(data1);
signerInfos[4] = signer2.genSignerInfo(new byte[]{});
signerInfos[3] = signer2.genSignerInfo(data2);
SimpleSigner signer3 = new SimpleSigner(null, null, null, null);
signerInfos[2] = signer3.genSignerInfo(data1);
signerInfos[1] = signer3.genSignerInfo(new byte[]{});
signerInfos[0] = signer3.genSignerInfo(data2);
ContentInfo contentInfo = new ContentInfo(data1);
AlgorithmId[] algIds = {new AlgorithmId(AlgorithmId.SHA256_oid)};
X509Certificate[] certs = {signer3.getCert(), signer2.getCert(),
signer1.getCert()};
PKCS7 pkcs71 = new PKCS7(algIds, contentInfo,
certs,
signerInfos);
System.out.println("SignerInfos in original.");
printSignerInfos(pkcs71.getSignerInfos());
DerOutputStream out = new DerOutputStream();
pkcs71.encodeSignedData(out);
PKCS7 pkcs72 = new PKCS7(out.toByteArray());
System.out.println("\nSignerInfos read back in:");
printSignerInfos(pkcs72.getSignerInfos());
System.out.println("Verified signers of original:");
SignerInfo[] verifs1 = pkcs71.verify();
System.out.println("Verified signers of after read-in:");
SignerInfo[] verifs2 = pkcs72.verify();
if (verifs1.length != verifs2.length) {
throw new RuntimeException("Length or Original vs read-in "
+ "should be same");
}
}
static void printSignerInfos(SignerInfo signerInfo) throws IOException {
ByteArrayOutputStream strm = new ByteArrayOutputStream();
signerInfo.derEncode(strm);
System.out.println("SignerInfo, length: "
+ strm.toByteArray().length);
System.out.println(hexDump.encode(strm.toByteArray()));
System.out.println("\n");
strm.reset();
}
static void printSignerInfos(SignerInfo[] signerInfos) throws IOException {
ByteArrayOutputStream strm = new ByteArrayOutputStream();
for (int i = 0; i < signerInfos.length; i++) {
signerInfos[i].derEncode(strm);
System.out.println("SignerInfo[" + i + "], length: "
+ strm.toByteArray().length);
System.out.println(hexDump.encode(strm.toByteArray()));
System.out.println("\n");
strm.reset();
}
}
}
/**
* A simple extension of sun.security.x509.X500Signer that adds a no-fuss
* signing algorithm.
*/
class SimpleSigner {
private final Signature sig;
private final X500Name agent;
private final AlgorithmId digestAlgId;
private final AlgorithmId encryptionAlgId;
private final AlgorithmId algId; // signature algid;
//combines digest + encryption
private final X509Key publicKey;
private final PrivateKey privateKey;
private final X509Certificate cert;
public SimpleSigner(String digestAlg,
String encryptionAlg,
KeyPair keyPair,
X500Name agent) throws Exception {
if (agent == null) {
agent = new X500Name("cn=test");
}
if (digestAlg == null) {
digestAlg = "SHA";
}
if (encryptionAlg == null) {
encryptionAlg = "DSA";
}
if (keyPair == null) {
KeyPairGenerator keyGen =
KeyPairGenerator.getInstance(encryptionAlg);
keyGen.initialize(1024);
keyPair = keyGen.generateKeyPair();
}
publicKey = (X509Key) keyPair.getPublic();
privateKey = keyPair.getPrivate();
if ("DSA".equals(encryptionAlg)) {
this.sig = Signature.getInstance(encryptionAlg);
} else { // RSA
this.sig = Signature.getInstance(digestAlg + "/" + encryptionAlg);
}
this.sig.initSign(privateKey);
this.agent = agent;
this.digestAlgId = AlgorithmId.get(digestAlg);
this.encryptionAlgId = AlgorithmId.get(encryptionAlg);
this.algId = AlgorithmId.get(this.sig.getAlgorithm());
this.cert = getSelfCert();
}
/**
* Take the data and sign it.
*
* @param buf buffer holding the next chunk of the data to be signed
* @param offset starting point of to-be-signed data
* @param len how many bytes of data are to be signed
* @return the signature for the input data.
* @exception SignatureException on errors.
*/
public byte[] simpleSign(byte[] buf, int offset, int len)
throws SignatureException {
sig.update(buf, offset, len);
return sig.sign();
}
/**
* Returns the digest algorithm used to sign.
*/
public AlgorithmId getDigestAlgId() {
return digestAlgId;
}
/**
* Returns the encryption algorithm used to sign.
*/
public AlgorithmId getEncryptionAlgId() {
return encryptionAlgId;
}
/**
* Returns the name of the signing agent.
*/
public X500Name getSigner() {
return agent;
}
public X509Certificate getCert() {
return cert;
}
private X509Certificate getSelfCert() throws Exception {
long validity = 1000;
X509CertImpl certLocal;
Date firstDate, lastDate;
firstDate = new Date();
lastDate = new Date();
lastDate.setTime(lastDate.getTime() + validity + 1000);
CertificateValidity interval = new CertificateValidity(firstDate,
lastDate);
X509CertInfo info = new X509CertInfo();
// Add all mandatory attributes
info.set(X509CertInfo.VERSION,
new CertificateVersion(CertificateVersion.V1));
info.set(X509CertInfo.SERIAL_NUMBER,
new CertificateSerialNumber(
(int) (firstDate.getTime() / 1000)));
info.set(X509CertInfo.ALGORITHM_ID,
new CertificateAlgorithmId(algId));
info.set(X509CertInfo.SUBJECT, agent);
info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
info.set(X509CertInfo.VALIDITY, interval);
info.set(X509CertInfo.ISSUER, agent);
certLocal = new X509CertImpl(info);
certLocal.sign(privateKey, algId.getName());
return certLocal;
}
public SignerInfo genSignerInfo(byte[] data) throws SignatureException {
return new SignerInfo((X500Name) cert.getIssuerDN(),
new BigInteger("" + cert.getSerialNumber()),
getDigestAlgId(), algId,
simpleSign(data, 0, data.length));
}
}