I have successfully generate pkcs7 signature ECDSAwithSHA256 using C# , but then i failed to verify signature using java
Here is sample class
public class TestVerify {
public static void main(String[] args) {
String Signature = "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";
String SigDateTime = "14-10-2020 10:58:22";
String certtype = "token";
String TimestampToken = "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";
String pdfhash = "faadTnFU4cOBsl+sW98ie7KInSbbw0HDbgFeOcsRCAQ=";
CMSSignedData signedDataTSToken = null;
TimeStampToken tstoken = null;
byte[] sigDataBytes = null;
Date sigDate = null;
CMSSignerHelper cmsHelper = new CMSSignerHelper();
CMSSignedData cmsData;
try {
sigDataBytes = Base64.getDecoder().decode(Signature);
cmsData = new CMSSignedData(sigDataBytes);
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
sigDate = formatter.parse(SigDateTime);
byte[] tsTokenDataBytes = Base64.getDecoder().decode(TimestampToken);
signedDataTSToken = new CMSSignedData(tsTokenDataBytes);
tstoken = new TimeStampToken(signedDataTSToken);
verifyCMSSignatureMTID(sigDataBytes, sigDate, TimestampToken, pdfhash);
} catch (Exception e) {
System.out.println("Exception : " + e);
}
}
public static void verifyCMSSignatureMTID(byte[] signature, Date signing_date, String encodedTimestampToken, String PdfHash) throws OperatorCreationException, CMSException, CertificateException, NoSuchAlgorithmException, ParseException, TSPException, IOException, Exception {
String fName="[verifyCMSSignatureMTID] ";
VSInfo vsi=new VSInfo();
String initErr="CMS";
//******************** VERIFY SGNATURE VS SIGNER PUBLICKEY **********************
// Verify signature
byte[] HashByte = Base64.getDecoder().decode(PdfHash);
CMSProcessableByteArray processable = new CMSProcessableByteArray(HashByte);
CMSSignedData cmsData = new CMSSignedData(signature);
X509CertificateHolder certHolder_v=null;
Security.addProvider(new BouncyCastleProvider());
try {
Store store = cmsData.getCertificates();
ByteArrayInputStream stream = new ByteArrayInputStream(signature);
CMSSignedData cms = new CMSSignedData(processable, stream);
SignerInformationStore signers = cms.getSignerInfos();
Collection c_v = signers.getSigners();
Iterator it_v = c_v.iterator();
while (it_v.hasNext()) {
SignerInformation signer_v = (SignerInformation) it_v.next();
Collection certCollection_v = store.getMatches(signer_v.getSID());
Iterator certIt_v = certCollection_v.iterator();
certHolder_v = (X509CertificateHolder) certIt_v.next();
X509Certificate certFromSignedData_v = new JcaX509CertificateConverter().getCertificate(certHolder_v);
if (signer_v.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build(certFromSignedData_v))) {
System.out.println(fName + "Signature verified");
} else {
System.out.println(fName + "Error CMS200 Signature is invalid");
System.out.println(initErr+"200");
System.out.println("Signature is invalid");
return;
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println(fName + "Error CMS200 Signature is invalid : " + e);
System.out.println("200");
System.out.println("Signature is invalid");
return;
}
System.out.println("000");
System.out.println("Signature is valid");
return;
}
}
Error
org.bouncycastle.operator.RuntimeOperatorException: exception
obtaining signature: error decoding signature bytes.
However, i have succesfully verify RSAwithSHA256 signature using this method. Can someone help me on this and kindly explain what that error is about. The signature length for those signature is 256byte for RSA and 64byte for ECDSA . is it correct?
Related
I have an API that creates Base64 digest of a PDF Document.
Now I want to create another API that takes this digest and PFX and creates an ETSI.CAdES.detached signature and takes LTV informations(Certs chain,OCSP response,CRL) that I want to embed in my PDF to obtain a PAdES-LTV signature using 3rd API(My 3rd API will take CAdES signature and LTV informations obtained from this API and will embed them in my PDF).I dont know how to create this ETSI.CAdES.detached signature using that digest and a PFX with Java and Bouncy Castle.I try to follow this github tutorial.
As you have declared, you have your own code for preparing a PDF for signing and for injecting the signature container into it. Thus, your question essentially burns down to
How to create a CAdES signature container with BouncyCastle that can be used to create a PAdES BASELINE B or T PDF signature?
Implementation in the iText 7 Signing Framework
As I do not have your existing code, I had to use a different framework for my tests. I used the iText 7 signing framework for that.
BouncyCastle does contain a CMSSignedDataGenerator to generate CMS signature containers.
The default implementation of the SignerInfo generation therein unfortunately is not CAdES/PAdES compatible as it does not create signed ESSCertID[v2] attributes. Fortunately, though, the implementation is designed to allow plugging in custom attributes sets.
Thus, you can create the CAdES containers required for PAdES BASELINE signatures with a customized CMSSignedDataGenerator.
So when you have prepared the PDF for signing, you can proceed like this:
InputStream data = [InputStream containing the PDF byte ranges to sign];
ContentSigner contentSigner = [BouncyCastle ContentSigner for your private key];
X509CertificateHolder x509CertificateHolder = [BouncyCastle X509CertificateHolder for your X.509 signer certificate];
DigestCalculatorProvider digestCalculatorProvider = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build();
CMSTypedData msg = new CMSTypedDataInputStream(data);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(digestCalculatorProvider)
.setSignedAttributeGenerator(new PadesSignedAttributeGenerator())
.setUnsignedAttributeGenerator(new PadesUnsignedAttributeGenerator())
.build(contentSigner, x509CertificateHolder));
gen.addCertificates(new JcaCertStore(Collections.singleton(x509CertificateHolder)));
CMSSignedData sigData = gen.generate(msg, false);
byte[] cmsBytes = sigData.getEncoded();
(PadesSignatureContainerBc method sign)
The byte[] cmsBytes contains the bytes to inject into the prepared PDF signature placeholder.
The following helper classes are needed:
First of all a wrapper for the InputStream containing the PDF ranges to sign to process by BouncyCastle.
class CMSTypedDataInputStream implements CMSTypedData {
InputStream in;
public CMSTypedDataInputStream(InputStream is) {
in = is;
}
#Override
public ASN1ObjectIdentifier getContentType() {
return PKCSObjectIdentifiers.data;
}
#Override
public Object getContent() {
return in;
}
#Override
public void write(OutputStream out) throws IOException,
CMSException {
byte[] buffer = new byte[8 * 1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
}
}
(PadesSignatureContainerBc helper class CMSTypedDataInputStream)
Then a customized signed attributes generator for PAdES:
class PadesSignedAttributeGenerator implements CMSAttributeTableGenerator {
#Override
public AttributeTable getAttributes(#SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
String currentAttribute = null;
try {
ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
currentAttribute = "SigningCertificateAttribute";
AlgorithmIdentifier digAlgId = (AlgorithmIdentifier) params.get(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER);
signedAttributes.add(createSigningCertificateAttribute(digAlgId));
currentAttribute = "ContentTypeAttribute";
ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance(params.get(CMSAttributeTableGenerator.CONTENT_TYPE));
signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(contentType)));
currentAttribute = "MessageDigestAttribute";
byte[] messageDigest = (byte[])params.get(CMSAttributeTableGenerator.DIGEST);
signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(messageDigest))));
return new AttributeTable(signedAttributes);
} catch (Exception e) {
throw new CMSAttributeTableGenerationException(currentAttribute, e);
}
}
Attribute createSigningCertificateAttribute(AlgorithmIdentifier digAlg) throws IOException, OperatorCreationException {
final IssuerSerial issuerSerial = getIssuerSerial();
DigestCalculator digestCalculator = digestCalculatorProvider.get(digAlg);
digestCalculator.getOutputStream().write(x509CertificateHolder.getEncoded());
final byte[] certHash = digestCalculator.getDigest();
if (OIWObjectIdentifiers.idSHA1.equals(digAlg.getAlgorithm())) {
final ESSCertID essCertID = new ESSCertID(certHash, issuerSerial);
SigningCertificate signingCertificate = new SigningCertificate(essCertID);
return new Attribute(id_aa_signingCertificate, new DERSet(signingCertificate));
} else {
ESSCertIDv2 essCertIdv2;
if (NISTObjectIdentifiers.id_sha256.equals(digAlg.getAlgorithm())) {
// SHA-256 is default
essCertIdv2 = new ESSCertIDv2(null, certHash, issuerSerial);
} else {
essCertIdv2 = new ESSCertIDv2(digAlg, certHash, issuerSerial);
}
SigningCertificateV2 signingCertificateV2 = new SigningCertificateV2(essCertIdv2);
return new Attribute(id_aa_signingCertificateV2, new DERSet(signingCertificateV2));
}
}
IssuerSerial getIssuerSerial() {
final X500Name issuerX500Name = x509CertificateHolder.getIssuer();
final GeneralName generalName = new GeneralName(issuerX500Name);
final GeneralNames generalNames = new GeneralNames(generalName);
final BigInteger serialNumber = x509CertificateHolder.getSerialNumber();
return new IssuerSerial(generalNames, serialNumber);
}
}
(PadesSignatureContainerBc helper class PadesSignedAttributeGenerator )
And finally a customized unsigned attributes generator for a signature timestamp:
class PadesUnsignedAttributeGenerator implements CMSAttributeTableGenerator {
#Override
public AttributeTable getAttributes(#SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
if (tsaClient == null)
return null;
try {
ASN1EncodableVector unsignedAttributes = new ASN1EncodableVector();
byte[] signature = (byte[])params.get(CMSAttributeTableGenerator.SIGNATURE);
byte[] timestamp = tsaClient.getTimeStampToken(tsaClient.getMessageDigest().digest(signature));
unsignedAttributes.add(new Attribute(id_aa_signatureTimeStampToken, new DERSet(ASN1Primitive.fromByteArray(timestamp))));
return new AttributeTable(unsignedAttributes);
} catch (Exception e) {
throw new CMSAttributeTableGenerationException("", e);
}
}
}
(PadesSignatureContainerBc helper class PadesUnsignedAttributeGenerator)
Here I assume a ITSAClient tsaClient, an iText 7 time stamp request client. You can of course use an arbitrary RFC 3161 time stamp request client of your choice.
If you have read your private key into a JCA/JCE PrivateKey pk, you can simply create the needed ContentSigner contentSigner using the BouncyCastle JcaContentSignerBuilder, e.g. like this:
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA512withRSA").build(pk);
(compare the test testSignPadesBaselineT in SignPadesBc)
Implementation in the PDFBox 3 Signing Framework
You meanwhile indicated in comments that you're looking into using PDFBox to sign. Fortunately the code presented above can nearly without a change be used with PDFBox.
To use the code above with PDFBox, one merely has to wrap it into a PDFBox SignatureInterface frame:
public class PadesSignatureContainerBc implements SignatureInterface {
public PadesSignatureContainerBc(X509CertificateHolder x509CertificateHolder, ContentSigner contentSigner, TSAClient tsaClient) throws OperatorCreationException {
this.contentSigner = contentSigner;
this.tsaClient = tsaClient;
this.x509CertificateHolder = x509CertificateHolder;
digestCalculatorProvider = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build();
}
#Override
public byte[] sign(InputStream content) throws IOException {
try {
CMSTypedData msg = new CMSTypedDataInputStream(content);
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(digestCalculatorProvider)
.setSignedAttributeGenerator(new PadesSignedAttributeGenerator())
.setUnsignedAttributeGenerator(new PadesUnsignedAttributeGenerator())
.build(contentSigner, x509CertificateHolder));
gen.addCertificates(new JcaCertStore(Collections.singleton(x509CertificateHolder)));
CMSSignedData sigData = gen.generate(msg, false);
return sigData.getEncoded();
} catch (OperatorCreationException | GeneralSecurityException | CMSException e) {
throw new IOException(e);
}
}
final ContentSigner contentSigner;
final X509CertificateHolder x509CertificateHolder;
final TSAClient tsaClient;
final DigestCalculatorProvider digestCalculatorProvider;
class CMSTypedDataInputStream implements CMSTypedData {
InputStream in;
public CMSTypedDataInputStream(InputStream is) {
in = is;
}
#Override
public ASN1ObjectIdentifier getContentType() {
return PKCSObjectIdentifiers.data;
}
#Override
public Object getContent() {
return in;
}
#Override
public void write(OutputStream out) throws IOException,
CMSException {
byte[] buffer = new byte[8 * 1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
}
}
class PadesSignedAttributeGenerator implements CMSAttributeTableGenerator {
#Override
public AttributeTable getAttributes(#SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
String currentAttribute = null;
try {
ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
currentAttribute = "SigningCertificateAttribute";
AlgorithmIdentifier digAlgId = (AlgorithmIdentifier) params.get(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER);
signedAttributes.add(createSigningCertificateAttribute(digAlgId));
currentAttribute = "ContentType";
ASN1ObjectIdentifier contentType = ASN1ObjectIdentifier.getInstance(params.get(CMSAttributeTableGenerator.CONTENT_TYPE));
signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(contentType)));
currentAttribute = "MessageDigest";
byte[] messageDigest = (byte[])params.get(CMSAttributeTableGenerator.DIGEST);
signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(messageDigest))));
return new AttributeTable(signedAttributes);
} catch (Exception e) {
throw new CMSAttributeTableGenerationException(currentAttribute, e);
}
}
Attribute createSigningCertificateAttribute(AlgorithmIdentifier digAlg) throws IOException, OperatorCreationException {
final IssuerSerial issuerSerial = getIssuerSerial();
DigestCalculator digestCalculator = digestCalculatorProvider.get(digAlg);
digestCalculator.getOutputStream().write(x509CertificateHolder.getEncoded());
final byte[] certHash = digestCalculator.getDigest();
if (OIWObjectIdentifiers.idSHA1.equals(digAlg.getAlgorithm())) {
final ESSCertID essCertID = new ESSCertID(certHash, issuerSerial);
SigningCertificate signingCertificate = new SigningCertificate(essCertID);
return new Attribute(id_aa_signingCertificate, new DERSet(signingCertificate));
} else {
ESSCertIDv2 essCertIdv2;
if (NISTObjectIdentifiers.id_sha256.equals(digAlg.getAlgorithm())) {
// SHA-256 is default
essCertIdv2 = new ESSCertIDv2(null, certHash, issuerSerial);
} else {
essCertIdv2 = new ESSCertIDv2(digAlg, certHash, issuerSerial);
}
SigningCertificateV2 signingCertificateV2 = new SigningCertificateV2(essCertIdv2);
return new Attribute(id_aa_signingCertificateV2, new DERSet(signingCertificateV2));
}
}
public IssuerSerial getIssuerSerial() {
final X500Name issuerX500Name = x509CertificateHolder.getIssuer();
final GeneralName generalName = new GeneralName(issuerX500Name);
final GeneralNames generalNames = new GeneralNames(generalName);
final BigInteger serialNumber = x509CertificateHolder.getSerialNumber();
return new IssuerSerial(generalNames, serialNumber);
}
}
class PadesUnsignedAttributeGenerator implements CMSAttributeTableGenerator {
#Override
public AttributeTable getAttributes(#SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
if (tsaClient == null)
return null;
try {
ASN1EncodableVector unsignedAttributes = new ASN1EncodableVector();
byte[] signature = (byte[])params.get(CMSAttributeTableGenerator.SIGNATURE);
byte[] timestamp = tsaClient.getTimeStampToken(new ByteArrayInputStream(signature)).getEncoded();
unsignedAttributes.add(new Attribute(id_aa_signatureTimeStampToken, new DERSet(ASN1Primitive.fromByteArray(timestamp))));
return new AttributeTable(unsignedAttributes);
} catch (Exception e) {
throw new CMSAttributeTableGenerationException("", e);
}
}
}
}
(PDFBox PadesSignatureContainerBc implementation of SignatureInterface)
You can use it like this
try ( PDDocument pdDocument = Loader.loadPDF(SOURCE_PDF) )
{
SignatureInterface signatureInterface = new PadesSignatureContainerBc(new X509CertificateHolder(chain[0].getEncoded()),
new JcaContentSignerBuilder("SHA512withRSA").build(pk),
new TSAClient(new URL("http://timestamp.server/rfc3161endpoint"), null, null, MessageDigest.getInstance("SHA-256")));
PDSignature signature = new PDSignature();
signature.setFilter(COSName.getPDFName("MKLx_PAdES_SIGNER"));
signature.setSubFilter(COSName.getPDFName("ETSI.CAdES.detached"));
signature.setName("Example User");
signature.setLocation("Los Angeles, CA");
signature.setReason("Testing");
signature.setSignDate(Calendar.getInstance());
pdDocument.addSignature(signature);
ExternalSigningSupport externalSigning = pdDocument.saveIncrementalForExternalSigning(RESULT_OUTPUT);
// invoke external signature service
byte[] cmsSignature = signatureInterface.sign(externalSigning.getContent());
// set signature bytes received from the service
externalSigning.setSignature(cmsSignature);
}
(PDFBox SignPadesBc test testSignPadesBaselineT)
I have a digitally signed pdf file and I am trying to verify the signature in that. But Signature is not getting verified. Below is the code
public static void main(String[] args) throws Exception {
HashMap<String, Object> keyPair = new HashMap<>();
String password = "123";
KeyStore keyStore = KeyStore.getInstance("pkcs12"); //, "BC");
keyStore.load(new FileInputStream("/Users/shivam/Documents/Projects/label-processor/src/main/resources/DigitalSignatureFile.pfx"), password.toCharArray());
Enumeration<String> keyStoreAliasEnum = keyStore.aliases();
String alias = null;
PublicKey publicKey = null;
PrivateKey privateKey = null;
byte[] signature = null;
while ( keyStoreAliasEnum.hasMoreElements() ) {
alias = keyStoreAliasEnum.nextElement();
if (password != null) {
privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
X509Certificate x509Certificate = (X509Certificate) keyStore.getCertificate(alias);
publicKey = x509Certificate.getPublicKey();
signature = x509Certificate.getSignature();
keyPair.put("Alias", alias);
keyPair.put("PublicKey", publicKey);
keyPair.put("PrivateKey", privateKey);
keyPair.put("X509Certificate", x509Certificate);
}
}
verify(publicKey, signature);
}
public static void verify(PublicKey publicKey, byte[] sigBytes) throws Exception {
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
FileInputStream datafis = new FileInputStream("/Users/shivam/Desktop/DigitallySignedFile.pdf");
byte[] data = IOUtils.toByteArray(datafis);
sig.update(data);
boolean verifies = sig.verify(sigBytes);
System.out.println("signature verifies: " + verifies);
FileUtils.writeByteArrayToFile(
new File("/Users/shivam/Documents/Projects/label-processor/src/main/resources/VerifiedFile.pdf"),
data
);
}
Above program is giving "Signature verifies: false". And In VerifiedFile.pdf I am still seeing signature not verified. But when I am trying to verify in Adobe Reader it is verifying correctly.
I tried verifying with the help of itext library also. It is verifying signature But In pdf it still shows signature not verified.
public static void main(String[] args) throws Exception {
byte[] pdfBytes = Files.readAllBytes(
Paths.get("/Users/shivam/Desktop/DigitallySignedFile.pdf")
);
PdfReader pdfReader = new PdfReader(pdfBytes);
AcroFields acroFields = pdfReader.getAcroFields();
List<String> signatures = acroFields.getSignatureNames();
boolean valid = false;
if (!signatures.isEmpty()) {
for (String signature : signatures) {
if (acroFields.signatureCoversWholeDocument(signature)) {
PdfPKCS7 pkcs7 = acroFields.verifySignature(signature);
valid = pkcs7.verify();
String reason = pkcs7.getReason();
Calendar signedAt = pkcs7.getSignDate();
X509Certificate x509Certificate = pkcs7.getSigningCertificate();
Principal issuerDN = x509Certificate.getIssuerDN();
Principal subjectDN = x509Certificate.getSubjectDN();
logger.info("valid = {}, date = {}, reason = '{}', issuer = '{}', subject = '{}'",
valid, signedAt.getTime(), reason, issuerDN, subjectDN);
break;
}
}
}
FileUtils.writeByteArrayToFile(
new File("/Users/shivam/Documents/Projects/label-processor/src/main/resources/VerifiedFile.pdf"),
pdfBytes
);
}
I appreciate any help.
We are trying to make the signed signature LTV enabled. I am using the below code to add verification. When signature.isTsp() is false, the PDF says Signature is not LTV enabled, though in the other case (signature.isTsp() is true) it shows as valid.
When we open the PDF and try to manually add verification info by right clicking on the signature it enables LTV without any issue. Not sure what we are missing here.
Any input will be highly helpful.
// Adds LTV-enabled information to the PDF document.
private ByteArrayOutputStream addLtv(final IOcspClient ocspClient,
final ByteArrayOutputStream docStream)
throws IOException, GeneralSecurityException {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final InputStream signedStream = new ByteArrayInputStream(docStream.toByteArray());
final PdfReader reader = new PdfReader(signedStream);
final PdfDocument document =
new PdfDocument(reader, new PdfWriter(outputStream), new StampingProperties().useAppendMode());
final LtvVerification verification = new LtvVerification(document);
final SignatureUtil signatureUtil = new SignatureUtil(document);
final List<String> signatureNames = signatureUtil.getSignatureNames();
final String sigName = signatureNames.get(signatureNames.size() - 1);
final PdfPKCS7 signature = signatureUtil.verifySignature(sigName);
final CrlClientOnline crl = new CrlClientOnline();
if (!signature.isTsp()) {
for (final String name: signatureNames) {
addVerificationInfo(ocspClient, verification, crl, name);
}
} else {
addVerificationInfo(ocspClient, verification, crl, sigName);
}
document.close();
return outputStream;
}
private void addVerificationInfo(final IOcspClient ocspClient, final LtvVerification verification,
final CrlClientOnline crl,
final String name) throws IOException, GeneralSecurityException {
verification.addVerification(
name, ocspClient, crl,
LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
The main reason why your code does not always LTV-enable PDFs is that it does not add validation information related to OCSP response signatures.
It doesn't add validation information for CRL signatures, either. As CRLs usually are signed by the issuer certificate of the signer certificate, though, and as validation information for that issuer certificate have already been added in the context of the main signature, LTV-enabling usually does not fail because of missing CRL signature validation information. So if you can use CRLs only, chances are that your code indeed already does LTV-enable PDFs.
In the context of this answer (in particular its section "An approach using an own utility class") I created an utility class AdobeLtvEnabling for iText 5 allowing to LTV-enable PDFs, mostly using bits and pieces found in iText 5 itself. In contrast to your code it does add validation information for OCSP response signatures (and also for CRL signatures).
Here you can find the port of that class to iText 7.
The utility class AdobeLtvEnabling
This utility class bundles the code required for LTV enabling the signatures in a signed PDF document. The code pieces mostly have been taken from existing iText code. The main reason why this class has not been designed to derive from LtvVerification is that required variables and methods from that class are private. As the class originally has been written for iText 5, some iText-5-isms probably can be found in it...
public class AdobeLtvEnabling {
/**
* Use this constructor with a {#link PdfDocument} in append mode. Otherwise
* the existing signatures will be damaged.
*/
public AdobeLtvEnabling(PdfDocument pdfDocument) {
this.pdfDocument = pdfDocument;
}
/**
* Call this method to have LTV information added to the {#link PdfDocument}
* given in the constructor.
*/
public void enable(IOcspClient ocspClient, ICrlClient crlClient) throws OperatorException, GeneralSecurityException, IOException, StreamParsingException, OCSPException {
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
List<String> names = signatureUtil.getSignatureNames();
for (String name : names) {
PdfPKCS7 pdfPKCS7 = signatureUtil.verifySignature(name, BouncyCastleProvider.PROVIDER_NAME);
PdfSignature sig = signatureUtil.getSignature(name);
List<X509Certificate> certificatesToCheck = new ArrayList<>();
certificatesToCheck.add(pdfPKCS7.getSigningCertificate());
while (!certificatesToCheck.isEmpty()) {
X509Certificate certificate = certificatesToCheck.remove(0);
addLtvForChain(certificate, ocspClient, crlClient, getSignatureHashKey(sig));
}
}
outputDss();
}
//
// the actual LTV enabling methods
//
void addLtvForChain(X509Certificate certificate, IOcspClient ocspClient, ICrlClient crlClient, PdfName key) throws GeneralSecurityException, IOException, StreamParsingException, OperatorCreationException, OCSPException {
ValidationData validationData = new ValidationData();
while (certificate != null) {
System.out.println(certificate.getSubjectX500Principal().getName());
X509Certificate issuer = getIssuerCertificate(certificate);
validationData.certs.add(certificate.getEncoded());
byte[] ocspResponse = ocspClient.getEncoded(certificate, issuer, null);
if (ocspResponse != null) {
System.out.println(" with OCSP response");
validationData.ocsps.add(ocspResponse);
X509Certificate ocspSigner = getOcspSignerCertificate(ocspResponse);
if (ocspSigner != null) {
System.out.printf(" signed by %s\n", ocspSigner.getSubjectX500Principal().getName());
}
addLtvForChain(ocspSigner, ocspClient, crlClient, getOcspHashKey(ocspResponse));
} else {
Collection<byte[]> crl = crlClient.getEncoded(certificate, null);
if (crl != null && !crl.isEmpty()) {
System.out.printf(" with %s CRLs\n", crl.size());
validationData.crls.addAll(crl);
for (byte[] crlBytes : crl) {
addLtvForChain(null, ocspClient, crlClient, getCrlHashKey(crlBytes));
}
}
}
certificate = issuer;
}
validated.put(key, validationData);
}
void outputDss() throws IOException {
PdfDictionary dss = new PdfDictionary();
PdfDictionary vrim = new PdfDictionary();
PdfArray ocsps = new PdfArray();
PdfArray crls = new PdfArray();
PdfArray certs = new PdfArray();
PdfCatalog catalog = pdfDocument.getCatalog();
if (pdfDocument.getPdfVersion().compareTo(PdfVersion.PDF_2_0) < 0) {
catalog.addDeveloperExtension(PdfDeveloperExtension.ESIC_1_7_EXTENSIONLEVEL5);
catalog.addDeveloperExtension(new PdfDeveloperExtension(PdfName.ADBE, new PdfName("1.7"), 8));
}
for (PdfName vkey : validated.keySet()) {
PdfArray ocsp = new PdfArray();
PdfArray crl = new PdfArray();
PdfArray cert = new PdfArray();
PdfDictionary vri = new PdfDictionary();
for (byte[] b : validated.get(vkey).crls) {
PdfStream ps = new PdfStream(b);
ps.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
ps.makeIndirect(pdfDocument);
crl.add(ps);
crls.add(ps);
crls.setModified();
}
for (byte[] b : validated.get(vkey).ocsps) {
b = buildOCSPResponse(b);
PdfStream ps = new PdfStream(b);
ps.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
ps.makeIndirect(pdfDocument);
ocsp.add(ps);
ocsps.add(ps);
ocsps.setModified();
}
for (byte[] b : validated.get(vkey).certs) {
PdfStream ps = new PdfStream(b);
ps.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
ps.makeIndirect(pdfDocument);
cert.add(ps);
certs.add(ps);
certs.setModified();
}
if (ocsp.size() > 0) {
ocsp.makeIndirect(pdfDocument);
vri.put(PdfName.OCSP, ocsp);
}
if (crl.size() > 0) {
crl.makeIndirect(pdfDocument);
vri.put(PdfName.CRL, crl);
}
if (cert.size() > 0) {
cert.makeIndirect(pdfDocument);
vri.put(PdfName.Cert, cert);
}
vri.put(PdfName.TU, new PdfDate().getPdfObject());
vri.makeIndirect(pdfDocument);
vrim.put(vkey, vri);
}
vrim.makeIndirect(pdfDocument);
vrim.setModified();
dss.put(PdfName.VRI, vrim);
if (ocsps.size() > 0) {
ocsps.makeIndirect(pdfDocument);
dss.put(PdfName.OCSPs, ocsps);
}
if (crls.size() > 0) {
crls.makeIndirect(pdfDocument);
dss.put(PdfName.CRLs, crls);
}
if (certs.size() > 0) {
certs.makeIndirect(pdfDocument);
dss.put(PdfName.Certs, certs);
}
dss.makeIndirect(pdfDocument);
dss.setModified();
catalog.put(PdfName.DSS, dss);
}
//
// VRI signature hash key calculation
//
static PdfName getCrlHashKey(byte[] crlBytes) throws NoSuchAlgorithmException, IOException, CRLException, CertificateException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(crlBytes));
byte[] signatureBytes = crl.getSignature();
DEROctetString octetString = new DEROctetString(signatureBytes);
byte[] octetBytes = octetString.getEncoded();
byte[] octetHash = hashBytesSha1(octetBytes);
PdfName octetName = new PdfName(convertToHex(octetHash));
return octetName;
}
static PdfName getOcspHashKey(byte[] basicResponseBytes) throws NoSuchAlgorithmException, IOException {
BasicOCSPResponse basicResponse = BasicOCSPResponse.getInstance(basicResponseBytes);
byte[] signatureBytes = basicResponse.getSignature().getBytes();
DEROctetString octetString = new DEROctetString(signatureBytes);
byte[] octetBytes = octetString.getEncoded();
byte[] octetHash = hashBytesSha1(octetBytes);
PdfName octetName = new PdfName(convertToHex(octetHash));
return octetName;
}
static PdfName getSignatureHashKey(PdfSignature sig) throws NoSuchAlgorithmException, IOException {
PdfString contents = sig.getContents();
byte[] bc = PdfEncodings.convertToBytes(contents.getValue(), null);
if (PdfName.ETSI_RFC3161.equals(sig.getSubFilter())) {
try ( ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(bc)) ) {
ASN1Primitive pkcs = din.readObject();
bc = pkcs.getEncoded();
}
}
byte[] bt = hashBytesSha1(bc);
return new PdfName(convertToHex(bt));
}
static byte[] hashBytesSha1(byte[] b) throws NoSuchAlgorithmException {
MessageDigest sh = MessageDigest.getInstance("SHA1");
return sh.digest(b);
}
static String convertToHex(byte[] bytes) {
ByteBuffer buf = new ByteBuffer();
for (byte b : bytes) {
buf.appendHex(b);
}
return PdfEncodings.convertToString(buf.toByteArray(), null).toUpperCase();
}
//
// OCSP response helpers
//
static X509Certificate getOcspSignerCertificate(byte[] basicResponseBytes) throws CertificateException, OCSPException, OperatorCreationException {
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
BasicOCSPResponse borRaw = BasicOCSPResponse.getInstance(basicResponseBytes);
BasicOCSPResp bor = new BasicOCSPResp(borRaw);
for (final X509CertificateHolder x509CertificateHolder : bor.getCerts()) {
X509Certificate x509Certificate = converter.getCertificate(x509CertificateHolder);
JcaContentVerifierProviderBuilder jcaContentVerifierProviderBuilder = new JcaContentVerifierProviderBuilder();
jcaContentVerifierProviderBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
final PublicKey publicKey = x509Certificate.getPublicKey();
ContentVerifierProvider contentVerifierProvider = jcaContentVerifierProviderBuilder.build(publicKey);
if (bor.isSignatureValid(contentVerifierProvider))
return x509Certificate;
}
return null;
}
static byte[] buildOCSPResponse(byte[] BasicOCSPResponse) throws IOException {
DEROctetString doctet = new DEROctetString(BasicOCSPResponse);
ASN1EncodableVector v2 = new ASN1EncodableVector();
v2.add(OCSPObjectIdentifiers.id_pkix_ocsp_basic);
v2.add(doctet);
ASN1Enumerated den = new ASN1Enumerated(0);
ASN1EncodableVector v3 = new ASN1EncodableVector();
v3.add(den);
v3.add(new DERTaggedObject(true, 0, new DERSequence(v2)));
DERSequence seq = new DERSequence(v3);
return seq.getEncoded();
}
//
// X509 certificate related helpers
//
static X509Certificate getIssuerCertificate(X509Certificate certificate) throws IOException, StreamParsingException {
String url = getCACURL(certificate);
if (url != null && url.length() > 0) {
HttpURLConnection con = (HttpURLConnection)new URL(url).openConnection();
if (con.getResponseCode() / 100 != 2) {
throw new PdfException(PdfException.InvalidHttpResponse1).setMessageParams(con.getResponseCode());
}
InputStream inp = (InputStream) con.getContent();
X509CertParser parser = new X509CertParser();
parser.engineInit(new ByteArrayInputStream(StreamUtil.inputStreamToArray(inp)));
return (X509Certificate) parser.engineRead();
}
return null;
}
static String getCACURL(X509Certificate certificate) {
ASN1Primitive obj;
try {
obj = getExtensionValue(certificate, Extension.authorityInfoAccess.getId());
if (obj == null) {
return null;
}
ASN1Sequence AccessDescriptions = (ASN1Sequence) obj;
for (int i = 0; i < AccessDescriptions.size(); i++) {
ASN1Sequence AccessDescription = (ASN1Sequence) AccessDescriptions.getObjectAt(i);
if ( AccessDescription.size() != 2 ) {
continue;
}
else if (AccessDescription.getObjectAt(0) instanceof ASN1ObjectIdentifier) {
ASN1ObjectIdentifier id = (ASN1ObjectIdentifier)AccessDescription.getObjectAt(0);
if ("1.3.6.1.5.5.7.48.2".equals(id.getId())) {
ASN1Primitive description = (ASN1Primitive)AccessDescription.getObjectAt(1);
String AccessLocation = getStringFromGeneralName(description);
if (AccessLocation == null) {
return "" ;
}
else {
return AccessLocation ;
}
}
}
}
} catch (IOException e) {
return null;
}
return null;
}
static ASN1Primitive getExtensionValue(X509Certificate certificate, String oid) throws IOException {
byte[] bytes = certificate.getExtensionValue(oid);
if (bytes == null) {
return null;
}
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
return aIn.readObject();
}
static String getStringFromGeneralName(ASN1Primitive names) throws IOException {
ASN1TaggedObject taggedObject = (ASN1TaggedObject) names ;
return new String(ASN1OctetString.getInstance(taggedObject, false).getOctets(), "ISO-8859-1");
}
//
// inner class
//
static class ValidationData {
final List<byte[]> crls = new ArrayList<byte[]>();
final List<byte[]> ocsps = new ArrayList<byte[]>();
final List<byte[]> certs = new ArrayList<byte[]>();
}
//
// member variables
//
final PdfDocument pdfDocument;
final Map<PdfName,ValidationData> validated = new HashMap<PdfName,ValidationData>();
}
(AdobeLtvEnabling.java)
Example use
You can use the AdobeLtvEnabling class like this:
try ( PdfReader pdfReader = new PdfReader(SOURCE);
PdfWriter pdfWriter = new PdfWriter(TARGET);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter,
new StampingProperties().preserveEncryption().useAppendMode())) {
AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(pdfDocument);
IOcspClient ocsp = new OcspClientBouncyCastle(null);
ICrlClient crl = new CrlClientOnline();
adobeLtvEnabling.enable(ocsp, crl);
}
(MakeLtvEnabled test testLtvEnableSignWithoutLtv)
Limitations
As this code essentially is ported from the iText 5 code from the referenced answer, it also inherits the limitations listed in that answer:
The code works under some simplifying restrictions, in particular:
signature time stamps are ignored,
retrieved CRLs are assumed to be direct and complete,
the complete certificate chains are assumed to be buildable using AIA entries.
You can improve the code accordingly if these restrictions are not acceptable for you.
I have three kinds of files to decode namely .csr and .der and .key files.I am able to decode .der file using the java as below.
public class Base64Decoder {
public static void main(String[] args) throws FileNotFoundException, IOException {
Certificate cert=null;
try{
FileInputStream fis = new FileInputStream("C:/Users/patillat/Downloads/device-ee/csr/00db1234567890A5-ka.der");
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
cert = cf.generateCertificate(bis);
try {
System.out.println("-----BEGIN CERTIFICATE-----");
System.out.println(DatatypeConverter.printBase64Binary(cert.getEncoded()));
System.out.println("-----END CERTIFICATE-----");
//System.out.println("key:"+cert.getPublicKey());
} catch (CertificateEncodingException e) {
e.printStackTrace();
}
System.out.println(cert.toString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
I am able to generate details of .der certificate
In the same way I am not able to decode my .csr file.
Are there any other ways to decode .csr files?
Using BouncyCastle you can easily decode a csr, from binary format.
JcaPKCS10CertificationRequest p10Object = new JcaPKCS10CertificationRequest(byte[] csrBytes);
There are also htlper classes for decoding/decoding to/from PEM format (base64 encoded).
Here's the code that I have used to decode .csr file.
public class CSRInfoDecoder {
private static Logger LOG = Logger.getLogger(CSRInfoDecoder.class.getName());
private static final String COUNTRY = "2.5.4.6";
private static final String STATE = "2.5.4.8";
private static final String LOCALE = "2.5.4.7";
private static final String ORGANIZATION = "2.5.4.10";
private static final String ORGANIZATION_UNIT = "2.5.4.11";
private static final String COMMON_NAME = "2.5.4.3";
private static final String EMAIL = "2.5.4.9";
private static final String csrPEM = "-----BEGIN CERTIFICATE REQUEST-----\n"
+ "MIICxDCCAawCAQAwfzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw\n"
+ "DgYDVQQHDAdDaGljYWdvMQ4wDAYDVQQKDAVDb2RhbDELMAkGA1UECwwCTkExDjAM\n"
+ "BgNVBAMMBUNvZGFsMR4wHAYJKoZIhvcNAQkBFg9rYmF4aUBjb2RhbC5jb20wggEi\n"
+ "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSrEF27VvbGi5x7LnPk4hRigAW\n"
+ "1feGeKOmRpHd4j/kUcJZLh59NHJHg5FMF7u9YdZgnMdULawFVezJMLSJYJcCAdRR\n"
+ "hSN+skrQlB6f5wgdkbl6ZfNaMZn5NO1Ve76JppP4gl0rXHs2UkRJeb8lguOpJv9c\n"
+ "tw+Sn6B13j8jF/m/OhIYI8fWhpBYvDXukgADTloCjOIsAvRonkIpWS4d014deKEe\n"
+ "5rhYX67m3H7GtZ/KVtBKhg44ntvuT2fR/wB1FlDws+0gp4edlkDlDml1HXsf4FeC\n"
+ "ogijo6+C9ewC2anpqp9o0CSXM6BT2I0h41PcQPZ4EtAc4ctKSlzTwaH0H9MbAgMB\n"
+ "AAGgADANBgkqhkiG9w0BAQsFAAOCAQEAqfQbrxc6AtjymI3TjN2upSFJS57FqPSe\n"
+ "h1YqvtC8pThm7MeufQmK9Zd+Lk2qnW1RyBxpvWe647bv5HiQaOkGZH+oYNxs1XvM\n"
+ "y5huq+uFPT5StbxsAC9YPtvD28bTH7iXR1b/02AK2rEYT8a9/tCBCcTfaxMh5+fr\n"
+ "maJtj+YPHisjxKW55cqGbotI19cuwRogJBf+ZVE/4hJ5w/xzvfdKjNxTcNr1EyBE\n"
+ "8ueJil2Utd1EnVrWbmHQqnlAznLzC5CKCr1WfmnrDw0GjGg1U6YpjKBTc4MDBQ0T\n"
+ "56ZL2yaton18kgeoWQVgcbK4MXp1kySvdWq0Bc3pmeWSM9lr/ZNwNQ==\n"
+ "-----END CERTIFICATE REQUEST-----\n";
public static void main(String[] args) {
InputStream stream = new ByteArrayInputStream(csrPEM.getBytes(StandardCharsets.UTF_8));
CSRInfoDecoder m = new CSRInfoDecoder();
m.readCertificateSigningRequest(stream);
}
public String readCertificateSigningRequest(InputStream csrStream) {
PKCS10CertificationRequest csr = convertPemToPKCS10CertificationRequest(csrStream);
String compname = null;
if (csr == null) {
LOG.warn("FAIL! conversion of Pem To PKCS10 Certification Request");
} else {
X500Name x500Name = csr.getSubject();
System.out.println("x500Name is: " + x500Name + "\n");
RDN cn = x500Name.getRDNs(BCStyle.EmailAddress)[0];
System.out.println(cn.getFirst().getValue().toString());
System.out.println(x500Name.getRDNs(BCStyle.EmailAddress)[0]);
System.out.println("COUNTRY: " + getX500Field(COUNTRY, x500Name));
System.out.println("STATE: " + getX500Field(STATE, x500Name));
System.out.println("LOCALE: " + getX500Field(LOCALE, x500Name));
System.out.println("ORGANIZATION: " + getX500Field(ORGANIZATION, x500Name));
System.out.println("ORGANIZATION_UNIT: " + getX500Field(ORGANIZATION_UNIT, x500Name));
System.out.println("COMMON_NAME: " + getX500Field(COMMON_NAME, x500Name));
System.out.println("EMAIL: " + getX500Field(EMAIL, x500Name));
}
return compname;
}
private String getX500Field(String asn1ObjectIdentifier, X500Name x500Name) {
RDN[] rdnArray = x500Name.getRDNs(new ASN1ObjectIdentifier(asn1ObjectIdentifier));
String retVal = null;
for (RDN item : rdnArray) {
retVal = item.getFirst().getValue().toString();
}
return retVal;
}
private PKCS10CertificationRequest convertPemToPKCS10CertificationRequest(InputStream pem) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
PKCS10CertificationRequest csr = null;
ByteArrayInputStream pemStream = null;
pemStream = (ByteArrayInputStream) pem;
Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
PEMParser pemParser = null;
try {
pemParser = new PEMParser(pemReader);
Object parsedObj = pemParser.readObject();
System.out.println("PemParser returned: " + parsedObj);
if (parsedObj instanceof PKCS10CertificationRequest) {
csr = (PKCS10CertificationRequest) parsedObj;
}
} catch (IOException ex) {
LOG.error("IOException, convertPemToPublicKey", ex);
} finally {
if (pemParser != null) {
IOUtils.closeQuietly(pemParser);
}
}
return csr;
}
}
In the above code, I have converted the csrPem String into a InputStream for my own testing purposes so you can eliminate that step and directly useByteArrayInputStream`.
One can utilize Bouncycastle in order to achieve this. See code snippet below for parsing a String to a PKCS10CertificationRequest. Of course you can replace the ByteArrayInputStream to a arbitrary input stream of your choice.
try (final ByteArrayInputStream bais = new ByteArrayInputStream(csrAsString.getBytes());
final InputStreamReader isr = new InputStreamReader(bais, StandardCharsets.UTF_8);
final PEMParser pem = new PEMParser(isr))
{
PKCS10CertificationRequest csr = (PKCS10CertificationRequest) pem.readObject();
// Do your verification here
}
I am unable to connect the google storage api through java class. any one provide sample code for this
#SuppressWarnings("serial")
public class GoogleServlet {
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private static final String PROJECT_ID = "";
public static String Base64Encoding()
throws java.security.SignatureException, UnsupportedEncodingException {
String access_id = "GOOG37E2YNNQW6FIGGDS ";
String secret_key = URLEncoder.encode("","UTF-8");
String bucket = "";
String version_header = "x-goog-api-version:1";
String project_header = "x-goog-project-id:"+PROJECT_ID;
String canonicalizedResources = "/"+bucket+"/";
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 30);
long expiration = calendar.getTimeInMillis();
String stringToSign = URLEncoder.encode("GET\n\n\n"+expiration+"\n"+version_header+"\n"+project_header+"\n"+canonicalizedResources,"UTF-8");
//String stringToSign = URLEncoder.encode("GET\n\n\n"+getdate()+"\n"+version_header+"\n"+project_header+"\n"+canonicalizedResources,"UTF-8");
String authSignature="";
try {
SecretKeySpec signingKey = new SecretKeySpec(secret_key.getBytes(),HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(stringToSign.getBytes("UTF-8"));
// base64-encode the hmac
authSignature = new String(Base64.encodeBase64(rawHmac));
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
authSignature = (access_id +":"+ authSignature);
return authSignature;
}
public static void main(String[] args) {
ClientConfig config = new DefaultClientConfig();-->ClientConfig cannot be resolved to a type
Client client = Client.create(config);
String authSignature = null;
try {
authSignature = "GOOG1 "+ Base64Encoding();
} catch (SignatureException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
WebResource service = client.resource(getBaseURI());
ClientResponse response = service.accept(MediaType.APPLICATION_XML)-->ClientResponse cannot be resolved to a type
.header("Authorization",authSignature)
.header("Date", getdate())
.header("Content-Length", "0")
.header("x-goog-api-version", "1")
.header("x-goog-project-id", PROJECT_ID)
.get(ClientResponse.class);
System.out.println(response.getClientResponseStatus().getFamily());
System.out.println("response1 :: " + response.getEntity(String.class));
}
private static URI getBaseURI() {
String url = "https://storage.cloud.google.com/mss/";
return UriBuilder.fromUri(url).build();--->The method resource(URI) is undefined for the type Client
}
private static String getdate(){
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z ", new Locale("US"));
Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
format.setCalendar(cal);
return format.format(new Date(0));
}
}
Error:
StringToSign : GET%0A%0A%0A1375378824994%0Ax-goog-api-version%3A1%0Ax-goog-project-id%3A883684764795%0A%2Fmss%2F
Auth Signature : GOOG1 GOOG37E2YNNQW6FIGGDS:3WcA0BQodfq0NrFenFilgJi1tq8=
CLIENT_ERROR
response1 :: <?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>GET
Your secret key is empty:
String secret_key = URLEncoder.encode("","UTF-8");
So signing key is also wrong
SecretKeySpec signingKey = new SecretKeySpec(secret_key.getBytes(),HMAC_SHA1_ALGORITHM);