/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
/**
* This class implements a content signing service.
* It generates a timestamped signature for a given content according to
* <a href="http://www.ietf.org/rfc/rfc3161.txt">RFC 3161</a>.
* The signature along with a trusted timestamp and the signer's certificate
* are all packaged into a standard PKCS #7 Signed Data message.
*
* @author Vincent Ryan
*/
/*
* Random number generator for creating nonce values
*/
static {
try {
} catch (NoSuchAlgorithmException e) {
// should not happen
}
}
/*
* Object identifier for the subject information access X.509 certificate
* extension.
*/
/*
* Object identifier for the timestamping key purpose.
*/
/*
* Object identifier for extendedKeyUsage extension
*/
/*
* Object identifier for the timestamping access descriptors.
*/
static {
try {
} catch (IOException e) {
// ignore
}
}
/*
* Location of the TSA.
*/
/*
* TSA's X.509 certificate.
*/
/*
* Generates an SHA-1 hash value for the data to be timestamped.
*/
/*
* Parameters for the timestamping protocol.
*/
private boolean tsRequestCertificate = true;
/**
* Instantiates a content signer that supports timestamped signatures.
*/
public TimestampedSigner() {
}
/**
* Generates a PKCS #7 signed data message that includes a signature
* timestamp.
* This method is used when a signature has already been generated.
* The signature, a signature timestamp, the signer's certificate chain,
* and optionally the content that was signed, are packaged into a PKCS #7
* signed data message.
*
* @param parameters The non-null input parameters.
* @param omitContent true if the content should be omitted from the
* signed data message. Otherwise the content is included.
* @param applyTimestamp true if the signature should be timestamped.
* Otherwise timestamping is not performed.
* @return A PKCS #7 signed data message including a signature timestamp.
* @throws NoSuchAlgorithmException The exception is thrown if the signature
* algorithm is unrecognised.
* @throws CertificateException The exception is thrown if an error occurs
* while processing the signer's certificate or the TSA's
* certificate.
* @throws IOException The exception is thrown if an error occurs while
* generating the signature timestamp or while generating the signed
* data message.
* @throws NullPointerException The exception is thrown if parameters is
* null.
*/
boolean omitContent, boolean applyTimestamp)
if (parameters == null) {
throw new NullPointerException();
}
// Parse the signature algorithm to extract the digest and key
// algorithms. The expected format is:
// "<digest>with<encryption>"
// or "<digest>with<encryption>and<mgf>"
// Examine signer's certificate
if (!(issuerName instanceof X500Name)) {
// must extract the original encoded form of DN for subsequent
// name comparison checks (converting to a String and back to
// an encoded DN could cause the types of String attribute
// values to be changed)
X509CertInfo tbsCert = new
issuerName = (Principal)
}
// Include or exclude content
if (omitContent) {
} else {
}
// Generate the timestamp token
if (applyTimestamp) {
} else {
// Examine TSA cert
throw new CertificateException(
"Subject Information Access extension not found");
}
}
// Timestamp the signature
// Insert the timestamp token into the PKCS #7 signer info element
// (as an unsigned attribute)
new PKCS9Attributes(new PKCS9Attribute[]{
new PKCS9Attribute(
tsToken)});
} else {
}
// Create the PKCS #7 signed data message
null, signerInfos);
return p7out.toByteArray();
}
/**
* Examine the certificate for a Subject Information Access extension
* (<a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280</a>).
* The extension's <tt>accessMethod</tt> field should contain the object
* identifier defined for timestamping: 1.3.6.1.5.5.7.48.3 and its
* <tt>accessLocation</tt> field should contain an HTTP or HTTPS URL.
*
* @param tsaCertificate An X.509 certificate for the TSA.
* @return An HTTP or HTTPS URL or null if none was found.
*/
if (tsaCertificate == null) {
return null;
}
// Parse the extensions
try {
byte[] extensionValue =
if (extensionValue == null) {
return null;
}
}
}
}
}
} catch (IOException ioe) {
// ignore
}
return null;
}
/*
* Returns a timestamp token from a TSA for the given content.
* Performs a basic check on the token to confirm that it has been signed
* by a certificate that is permitted to sign timestamps.
*
* @param toBeTimestamped The data to be timestamped.
* @throws IOException The exception is throw if an error occurs while
* communicating with the TSA.
* @throws CertificateException The exception is throw if the TSA's
* certificate is not permitted for timestamping.
*/
throws CertificateException, IOException {
// Generate hash value for the data to be timestamped
// SHA-1 is always used.
if (messageDigest == null) {
try {
} catch (NoSuchAlgorithmException e) {
// ignore
}
}
// Generate a timestamp
// Generate a nonce
}
// Handle TSP error
if (failureCode == -1) {
throw new IOException("Error generating timestamp: " +
} else {
throw new IOException("Error generating timestamp: " +
}
}
throw new IOException("Digest algorithm not SHA-1 in timestamp token");
}
throw new IOException("Digest octets changed in timestamp token");
};
throw new IOException("Nonce missing in timestamp token");
}
throw new IOException("Nonce changed in timestamp token");
}
// Examine the TSA's certificate (if present)
// Error, we've already set tsRequestCertificate = true
throw new CertificateException(
"Certificate not included in timestamp token");
} else {
throw new CertificateException(
"Certificate is not valid for timestamping");
}
if (keyPurposes == null ||
throw new CertificateException(
"Certificate is not valid for timestamping");
}
}
}
return tsReply.getEncodedToken();
}
}