001/* 002 * Copyright 2014 Emmanuel Bourg 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package net.jsign.timestamp; 018 019import java.io.IOException; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.Map; 023 024import org.bouncycastle.asn1.DERSet; 025import org.bouncycastle.asn1.cms.Attribute; 026import org.bouncycastle.asn1.cms.CMSAttributes; 027import org.bouncycastle.cert.X509CertificateHolder; 028import org.bouncycastle.cms.CMSSignedData; 029import org.bouncycastle.cms.SignerInformation; 030import org.bouncycastle.util.encoders.Base64; 031 032import net.jsign.DigestAlgorithm; 033import net.jsign.asn1.authenticode.AuthenticodeTimeStampRequest; 034 035/** 036 * Legacy Authenticode timestamping. 037 * 038 * @author Emmanuel Bourg 039 * @since 1.3 040 */ 041public class AuthenticodeTimestamper extends Timestamper { 042 043 public AuthenticodeTimestamper() { 044 setURL("http://timestamp.sectigo.com"); 045 } 046 047 protected CMSSignedData timestamp(DigestAlgorithm algo, byte[] encryptedDigest) throws IOException, TimestampingException { 048 AuthenticodeTimeStampRequest timestampRequest = new AuthenticodeTimeStampRequest(encryptedDigest); 049 050 byte[] request = Base64.encode(timestampRequest.getEncoded("DER")); 051 Map<String, String> headers = new HashMap<>(); 052 headers.put("Content-Type", "application/octet-stream"); 053 headers.put("Accept", "application/octet-stream"); 054 byte[] response = post(tsaurl, request, headers); 055 056 try { 057 return new CMSSignedData(Base64.decode(response)); 058 } catch (Exception e) { 059 throw new TimestampingException("Unable to complete the timestamping", e); 060 } 061 } 062 063 @Override 064 protected Collection<X509CertificateHolder> getExtraCertificates(CMSSignedData token) { 065 return token.getCertificates().getMatches(null); 066 } 067 068 @Override 069 protected Attribute getCounterSignature(CMSSignedData token) { 070 SignerInformation timestampSignerInformation = token.getSignerInfos().getSigners().iterator().next(); 071 return new Attribute(CMSAttributes.counterSignature, new DERSet(timestampSignerInformation.toASN1Structure())); 072 } 073}