I am currently using bouncy castle to create a PKCS10 request with a single subject as such:
X500Principal subject = new X500Principal("CN=foo.bar.com");
PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(
subject, publicKey);
I now need to add subject alternatives to the PKCS10 request. I have been unable to figure out how to do this. Any suggestions?
SOLUTION:
Based on the great info provided in the 2nd answer I was able to figure this out. In the working code below XName is a simple class holding the subject name and name type (DNS, RFC822, etc).
String signerAlgo = "SHA256withRSA";
ContentSigner signGen = new JcaContentSignerBuilder(signerAlgo).build(privateKey);
X500Principal subject = new X500Principal(csr.getSubjectAsX500NameString());
PKCS10CertificationRequestBuilder builder =
new JcaPKCS10CertificationRequestBuilder(subject, publicKey);
/*
* Add SubjectAlternativeNames (SANs)
*/
if (csr.getSubjectAlternatives() != null && csr.getSubjectAlternatives().size() > 0) {
List<GeneralName> namesList = new ArrayList<>();
for (XName subjectAlt : csr.getSubjectAlternatives()) {
log.debug(m, d+2, "Adding SubjectAltName: %s", subjectAlt);
namesList.add(GeneralNameTool.toGeneralName(subjectAlt));
}
/*
* Use ExtensionsGenerator to add individual extensions.
*/
ExtensionsGenerator extGen = new ExtensionsGenerator();
GeneralNames subjectAltNames = new GeneralNames(namesList.toArray(new GeneralName [] {}));
extGen.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
}
PKCS10CertificationRequest request = builder.build(signGen);
StringWriter writer = new StringWriter();
JcaPEMWriter pem = new JcaPEMWriter(writer);
pem.writeObject(request);
pem.close();
I had the same issue Mike, and I think your problem relates to trying to do this using a JcaPKCS10CertificationRequestBuilder (from the version 2 APIs) instead of by using the deprecated V1 APIs.
If you go to the BC wiki pages and look for "X.509 Public Key Certificate and Certificate request generation" there is a reasonable description of what to do with the Version 1 APIs, which is very similar to the listing on page 212 of the Wrox book by David Hook, "Beginning Cryptography with Java".
The documentation on the wiki for the version 2 APIs is really poor when describing how to create a CSR though.
To summarise how to use the v2 APIs, here's some code I have which works which is based on their V2 tests case (the class to look for is below this code listing):
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
...
X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);
// See e.g. http://javadox.com/org.bouncycastle/\
// bcprov-jdk15on/1.51/org/bouncycastle/asn1/x500/style/BCStyle.html
// for a description of the available RDNs
x500NameBld.addRDN(BCStyle.CN, commonName);
x500NameBld.addRDN(BCStyle.OU, orgCode);
x500NameBld.addRDN(BCStyle.UNIQUE_IDENTIFIER, "64 bit EUID goes here");
X500Name subject = x500NameBld.build();
/**
* My application needs to set the Key Usage section of the CSR
* (which for my app has a Criticality of "true" and a value of
* "digital signature" or "key agreement").
*/
Extension[] extSigning = new Extension[] {
new Extension(Extension.basicConstraints, true,
new DEROctetString(new BasicConstraints(true))),
new Extension(Extension.keyUsage, true,
new DEROctetString(new KeyUsage(KeyUsage.keyCertSign))),
};
Extension[] extKeyAgreement = new Extension[] {
new Extension(Extension.basicConstraints, true,
new DEROctetString(new BasicConstraints(true))),
new Extension(Extension.keyUsage, true,
new DEROctetString(new KeyUsage(KeyUsage.keyCertSign))),
};
PKCS10CertificationRequest req =
new JcaPKCS10CertificationRequestBuilder(
subject,
pair.getPublic())
.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
new Extensions(isKaFlag==true?extKeyAgreement:extSigning))
.build(new JcaContentSignerBuilder("SHA256withECDSA")
.setProvider(BC)
.build(pair.getPrivate()));
return req; // The PKCS10 certificate signing request
I'd suggest looking closely at their wiki pages specifically for the v2 API.
Critically, once you have found the source code for cert.test.PKCS10Test for V2 it all starts to make sense. Finally, I use this JavaScript hex dumper for ASN1
to check that it is coming out correctly.
Related
import java.util.Collections;
import java.util.Map;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.json.JSONObject;
import com.google.actions.api.smarthome.DisconnectRequest;
import com.google.actions.api.smarthome.ExecuteRequest;
import com.google.actions.api.smarthome.ExecuteResponse;
import com.google.actions.api.smarthome.QueryRequest;
import com.google.actions.api.smarthome.QueryResponse;
import com.google.actions.api.smarthome.SmartHomeApp;
import com.google.actions.api.smarthome.SyncRequest;
import com.google.actions.api.smarthome.SyncResponse;
import com.google.actions.api.smarthome.SyncResponse.Payload;
public class GoogleDeviceSync extends SmartHomeApp {
#NotNull
#Override
public SyncResponse onSync(#NotNull SyncRequest syncRequest, #Nullable Map<?, ?> map) {
Payload payload = new Payload();
payload.setAgentUserId("1836.15267389");
payload.setDevices(
new Device[] {
new Device.Builder()
.setId("123")
.setType("action.devices.types.OUTLET")
.addTrait("action.devices.traits.OnOff")
.setName(
Collections.singletonList("My Outlet 1234"),
"Night light",
Collections.singletonList("Wall plug"))
.setWillReportState(true)
.setDeviceInfo("lights-out-inc", "hs1234", "3.2", "11.4")
.setCustomData(
new JSONObject()
.put("fooValue", 74)
.put("barValue", true)
.put("bazValue", "foo"))
.build(),
new Device.Builder()
.setId("456")
.setType("action.devices.types.LIGHT")
.addTrait("action.devices.traits.OnOff")
.addTrait("action.devices.traits.Brightness")
.addTrait("action.devices.traits.ColorTemperature")
.addTrait("action.devices.traits.ColorSpectrum")
.setName(
Collections.singletonList("Lights Out Inc. bulb A19 color hyperglow"),
"Lamp",
Collections.singletonList("Reading lamp"))
.setWillReportState(true)
.setDeviceInfo("Lights Out Inc.", "hg11", "1.2", "5.4")
.setCustomData(
new JSONObject()
.put("fooValue", 12)
.put("barValue", false)
.put("bazValue", "bar"))
.build(),
});
return new SyncResponse(syncRequest.getRequestId(), payload);
}
}
Which jar is payload.setDevices(new Device[]) and Device introduced from?
From the https://developers.google.com/assistant/smarthome/develop/process-intents document, there is only code, and the introduction of jar is not shown. So which jar does'device' need to introduce
Adding dependencies (jars)
The dependency (the jar) that needs to be added in the gradle.build should be:
implementation 'com.google.actions:actions-on-google:1.8.0'
The specific version will depend on your configuration and environment.
You can see a full example gradle.build. In the same folder there are also other configuration examples.
Importing Classes
I also add some information on where the Payload and Device classes are.
Payload is nested inside SyncResponse and Device is nested inside Payload.
Payload is imported with the following import statement:
import com.google.actions.api.smarthome.SyncResponse.Payload
Device can be imported with the following import statement:
import com.google.actions.api.smarthome.SyncResponse.Payload.Device
Creating Objects
To create a new Payload from the Payload in the SyncResponse:
new SyncResponse.Payload()
And you can try to create a Device from its builder:
SyncResponse.Payload.Device.Builder deviceBuilder = new syncResponse.Payload.Device.Builder()
See this example for usage of the 'Payload' and 'Device'.
The following source is a JUnit-Test that shows the problem in question.
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Date;
import javax.mail.MessagingException;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationVerifier;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.mail.smime.SMIMESigned;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import junit.framework.TestCase;
/**
* Test class to check out S/MIME signature and verification
*/
public class __Run_SMIMESigning extends TestCase {
final static SecureRandom random = new SecureRandom();
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* Tests the issue
* #throws Exception
*/
public void testMailSigning() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
kpg.initialize(1024, random);
KeyPair aliceKey = kpg.generateKeyPair();
X509Certificate aliceCert = makeCertificate(aliceKey, "CN=Alice's Certiicate", aliceKey, "CN=Alice's Certiicate");
MimeBodyPart mbp = createMailBodyPart();
mbp.writeTo(System.out);
System.out.println();
SMIMESignedGenerator gen = new SMIMESignedGenerator();
JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC");
SignerInfoGenerator sigGen = builder.build("SHA256WithRSA", aliceKey.getPrivate(), aliceCert);
gen.addSignerInfoGenerator(sigGen);
MimeMultipart signedMM = gen.generate(mbp);
MimeBodyPart signedBody = new MimeBodyPart();
signedBody.setContent(signedMM, signedMM.getContentType());
System.out.println("signed:");
signedBody.writeTo(System.out);
System.out.println();
MimeMultipart content = (MimeMultipart) signedBody.getContent();
SMIMESigned sig = new SMIMESigned(content);
SignerInformation si = sig.getSignerInfos().getSigners().iterator().next();
SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(aliceCert);
System.out.println("verified: " + si.verify(verifier));
}
private MimeBodyPart createMailBodyPart() throws MessagingException {
MimeBodyPart plainText = new MimeBodyPart();
plainText.setText("Plain text with non-ascii: €", "utf8", "plain");
MimeBodyPart htmlText = new MimeBodyPart();
htmlText.setText("<h1>Some HTML</h1><p>Some text with non-ascii: €</p>", "utf8", "html");
MimeBodyPart alternatives = new MimeBodyPart();
alternatives.setContent(new MimeMultipart("alternative", plainText, htmlText));
MimeBodyPart textAttachment = new MimeBodyPart();
textAttachment.setText("some attachment data containing non-ascii-data like €", "utf8", "plain");
textAttachment.setHeader("Content-Transfer-Encoding", "base64");
textAttachment.setDisposition("attachment");
textAttachment.setFileName("filename.txt");
MimeBodyPart ret = new MimeBodyPart();
ret.setContent(new MimeMultipart(alternatives, textAttachment));
return ret;
}
// taken from the BC test case class
// at https://github.com/bcgit/bc-java/blob/master/mail/src/main/java/org/bouncycastle/mail/smime/examples/CreateSignedMultipartMail.java
static X509Certificate makeCertificate(
KeyPair subKP,
String subDN,
KeyPair issKP,
String issDN)
throws Exception
{
PublicKey subPub = subKP.getPublic();
PrivateKey issPriv = issKP.getPrivate();
PublicKey issPub = issKP.getPublic();
JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
X509v3CertificateBuilder v3CertGen = new JcaX509v3CertificateBuilder(new X500Name(issDN), BigInteger.valueOf(random.nextLong()), new Date(System.currentTimeMillis()), new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)), new X500Name(subDN), subPub);
v3CertGen.addExtension(
Extension.subjectKeyIdentifier,
false,
extUtils.createSubjectKeyIdentifier(subPub));
v3CertGen.addExtension(
Extension.authorityKeyIdentifier,
false,
extUtils.createAuthorityKeyIdentifier(issPub));
return new JcaX509CertificateConverter().setProvider("BC").getCertificate(v3CertGen.build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(issPriv)));
}
}
I'm creating a mail that is typical today:
multipart/mixed
multipart/alternative
text/plain mail body
text/html mail body
text/plain attachment with filename
I then use BouncyCastle to sign the whole thing. When I try to verify the signature immediately afterwards, it fails with the exception
org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value
at org.bouncycastle.cms.SignerInformation.doVerify(Unknown Source)
at org.bouncycastle.cms.SignerInformation.verify(Unknown Source)
at __Run_SMIMESigning.testMailSigning(__Run_SMIMESigning.java:77)
If I compress the multipart mime body before signing, the verification succeeds, so I think that my way of doing the signing should be correct in principle but I'm out of ideas what to do to get this particular use case to work.
My first test was done with BouncyCastle 1.54 but 1.62 (the current version) shows no difference in the result.
I am using this java program to validate a digital signature using public key (cer file). I am using opensaml 2.6.3 jars
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.validation.Schema;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.X509EncodedKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.opensaml.DefaultBootstrap;
import org.opensaml.common.xml.SAMLSchemaBuilder;
import org.opensaml.saml2.core.NewEncryptedID;
import org.opensaml.saml2.core.Response;
import org.opensaml.xml.Configuration;
import org.opensaml.xml.XMLObject;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.security.x509.BasicX509Credential;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.signature.SignatureValidator;
import org.opensaml.xml.validation.ValidationException;
public class FinalTester
{
public static void main(String[] args)
{
try
{
//initialize the opensaml library
DefaultBootstrap.bootstrap();
Schema schema = SAMLSchemaBuilder.getSAML11Schema();
//get parser pool manager
BasicParserPool parserPoolManager = new BasicParserPool();
parserPoolManager.setNamespaceAware(true);
parserPoolManager.setIgnoreElementContentWhitespace(true);
parserPoolManager.setSchema(schema);
////get KeyFactory object that creates key objects, specifying RSA
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
String state=
"PHNhbWxwOlJlc3BvbnNlIHhtbG5zOmFzcnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIElzc3VlSW5zdGFudD0iMjAxNC0xMC0xN1QxODo1MTowOC4yMjE5NTk1WiIgRGVzdGluYXRpb249Imh0dHBzOi8vcWEubGV4aXNuZXhpcy5jb20vc2FtbF9zaWduaW4iIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50OnVuc3BlY2lmaWVkIiBJRD0iY2VvZGtoaW1rZW9iaWdqb2ZqZ2hmY2djZGVubW5rbXBjbW1kZnBrZyIgVmVyc2lvbj0iMi4wIiB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj4NCgk8YXNydDpJc3N1ZXI+RGVsb2l0dGU8L2FzcnQ6SXNzdWVyPg0KCTxTaWduYXR1cmUgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPg0KCQk8U2lnbmVkSW5mbz4NCgkJCTxDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiAvPg0KCQkJPFNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSIgLz4NCgkJCTxSZWZlcmVuY2UgVVJJPSIjY2VvZGtoaW1rZW9iaWdqb2ZqZ2hmY2djZGVubW5rbXBjbW1kZnBrZyI+DQoJCQkJPFRyYW5zZm9ybXM+DQoJCQkJCTxUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIgLz4NCgkJCQkJPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgLz4NCgkJCQk8L1RyYW5zZm9ybXM+DQoJCQkJPERpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIiAvPg0KCQkJCTxEaWdlc3RWYWx1ZT5Xc0w2QU9nbEVmWVdneE9CNmJ6YXpWN2dnZkU9PC9EaWdlc3RWYWx1ZT4NCgkJCTwvUmVmZXJlbmNlPg0KCQk8L1NpZ25lZEluZm8+DQoJCTxTaWduYXR1cmVWYWx1ZT5FZXZ2MXQ5amZ3YmZNc0h2aXRuWXFXSldBS0RkWk9zRmNLK25xei8yd1A1TjlhNGdnNTZ5YzZBMjJISnh2aUQrRjEweVhCMjVkdG5xN1Rac1BlYUNMTlpVRWRzWjJSblNpTFZjTGRVeHg2SGs1STdFcDlibTBIRG5TYVpPV0Z4N2NBTnQ2WWJzNDZLKzJ1T3JwOVdRbDVoTkFOYmo3UWNaYWdZZnZtNmQ1MVR3ZFBwZ0NxQXNWc3BkeW4zRFlaUVpKL2ZQZDZCRGNuSWN5eU1qVkU4b3lra1dCL1VRN0h3aDd6NWFwYyt4cTU0S1FOM1NWUWlLVjM2TFJXdG5SVVp3Z3hEbUEyRERTYVlRQWpGM2VMZGpBeXhsOGxMTXdTajlNVHZMdTJmSHlDMGM2ZXBudHYzSnFVZmtYNktTRHg2Vm9hdjQxaGxzaEhwMW9wNUxqZ2JMMVE9PTwvU2lnbmF0dXJlVmFsdWU+DQoJPC9TaWduYXR1cmU+DQoJPHNhbWxwOlN0YXR1cz4NCgkJPHNhbWxwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIgLz4NCgk8L3NhbWxwOlN0YXR1cz4NCgk8YXNydDpBc3NlcnRpb24gSXNzdWVJbnN0YW50PSIyMDE0LTEwLTE3VDE4OjUxOjA4LjIyMTk1OTVaIiBJRD0iZ2tma2Rub2psZ2FrbXBwcGlkaWVoYWVobWJobGVrZGNiZGhmZ2FoaCIgVmVyc2lvbj0iMi4wIj4NCgkJPGFzcnQ6SXNzdWVyPkRlbG9pdHRlPC9hc3J0Oklzc3Vlcj4NCgkJPGFzcnQ6U3ViamVjdD4NCgkJCTxhc3J0Ok5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyI+YmhnYW5kaGlAdHN0LmRlbG9pdHRlLmNvbTwvYXNydDpOYW1lSUQ+DQoJCQk8YXNydDpTdWJqZWN0Q29uZmlybWF0aW9uIE1ldGhvZD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmNtOmJlYXJlciI+DQoJCQkJPGFzcnQ6U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgTm90T25PckFmdGVyPSIyMDE0LTEwLTE3VDE4OjU2OjA4LjIyMTk1OTVaIiBSZWNpcGllbnQ9Imh0dHBzOi8vcWEubGV4aXNuZXhpcy5jb20vc2FtbF9zaWduaW4iIC8+DQoJCQk8L2FzcnQ6U3ViamVjdENvbmZpcm1hdGlvbj4NCgkJPC9hc3J0OlN1YmplY3Q+DQoJCTxhc3J0OkNvbmRpdGlvbnMgTm90T25PckFmdGVyPSIyMDE0LTEwLTE3VDE4OjU2OjA4LjIyMTk1OTVaIiBOb3RCZWZvcmU9IjIwMTQtMTAtMTdUMTg6NDY6MDguMjIxOTU5NVoiPg0KCQkJPGFzcnQ6QXVkaWVuY2VSZXN0cmljdGlvbj4NCgkJCQk8YXNydDpBdWRpZW5jZT5odHRwczovL3FhLmxleGlzbmV4aXMuY29tL3NhbWxfc2lnbmluPC9hc3J0OkF1ZGllbmNlPg0KCQkJPC9hc3J0OkF1ZGllbmNlUmVzdHJpY3Rpb24+DQoJCTwvYXNydDpDb25kaXRpb25zPg0KCQk8YXNydDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iRmlyc3QgTmFtZSIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDpiYXNpYyI+DQoJCQkJPGFzcnQ6QXR0cmlidXRlVmFsdWUgeG1sbnM6cTE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIiBkNXAxOnR5cGU9InExOnN0cmluZyIgeG1sbnM6ZDVwMT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiPkJyZW50PC9hc3J0OkF0dHJpYnV0ZVZhbHVlPg0KCQkJPC9hc3J0OkF0dHJpYnV0ZT4NCgkJCTxhc3J0OkF0dHJpYnV0ZSBOYW1lPSJMYXN0IE5hbWUiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnEyPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxMjpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj5SdWJpbzwvYXNydDpBdHRyaWJ1dGVWYWx1ZT4NCgkJCTwvYXNydDpBdHRyaWJ1dGU+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iRW1haWwiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnEzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxMzpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj5iaGdhbmRoaUB0c3QuZGVsb2l0dGUuY29tPC9hc3J0OkF0dHJpYnV0ZVZhbHVlPg0KCQkJPC9hc3J0OkF0dHJpYnV0ZT4NCgkJCTxhc3J0OkF0dHJpYnV0ZSBOYW1lPSJQZXJzb25uZWxOdW1iZXIiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6YmFzaWMiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnE0PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxNDpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj4wMDMwNjg2NTwvYXNydDpBdHRyaWJ1dGVWYWx1ZT4NCgkJCTwvYXNydDpBdHRyaWJ1dGU+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iUGVyc29uSUQiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dW5zcGVjaWZpZWQiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnE1PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxNTpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj5QZXJzb25JRDwvYXNydDpBdHRyaWJ1dGVWYWx1ZT4NCgkJCTwvYXNydDpBdHRyaWJ1dGU+DQoJCQk8YXNydDpBdHRyaWJ1dGUgTmFtZT0iTG9jYXRpb24iIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dW5zcGVjaWZpZWQiPg0KCQkJCTxhc3J0OkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnE2PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgZDVwMTp0eXBlPSJxNjpzdHJpbmciIHhtbG5zOmQ1cDE9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIj4xNC8xNFMwNTNBPC9hc3J0OkF0dHJpYnV0ZVZhbHVlPg0KCQkJPC9hc3J0OkF0dHJpYnV0ZT4NCgkJPC9hc3J0OkF0dHJpYnV0ZVN0YXRlbWVudD4NCgkJPGFzcnQ6QXV0aG5TdGF0ZW1lbnQgU2Vzc2lvbkluZGV4PSJiZWNpcGxlbW5lbGRwa2JhaWhtaGhmZmVpcG5maGtwam1tYm1lYWhuIiBBdXRobkluc3RhbnQ9IjIwMTQtMTAtMTdUMTg6NTE6MDguMjIxOTU5NVoiPg0KCQkJPGFzcnQ6QXV0aG5Db250ZXh0Pg0KCQkJCTxhc3J0OkF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphYzpjbGFzc2VzOkludGVybmV0UHJvdG9jb2w8L2FzcnQ6QXV0aG5Db250ZXh0Q2xhc3NSZWY+DQoJCQk8L2FzcnQ6QXV0aG5Db250ZXh0Pg0KCQk8L2FzcnQ6QXV0aG5TdGF0ZW1lbnQ+DQoJPC9hc3J0OkFzc2VydGlvbj4NCjwvc2FtbHA6UmVzcG9uc2U+";
byte[] xmlString = Base64.decodeBase64(state);
String s = new String(xmlString);
Document document = parserPoolManager.parse(new ByteArrayInputStream(s.getBytes("UTF-8")));
Element metadataRoot = (Element) document.getDocumentElement();
QName qName= new QName(metadataRoot.getNamespaceURI(), metadataRoot.getLocalName(), metadataRoot.getPrefix());
// //get an unmarshaller
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(qName);
// //unmarshall using the document root element
Response response = (Response)unmarshaller.unmarshall(metadataRoot);
//get the signature to validate from the response object
Signature signature = response.getSignature();
/***************************************************************************************************/
//grab the certificate file
File certificateFile = new File("C:\\samlwork\\domain.com_B64.cer");
//get the certificate from the file
InputStream inputStream2 = new FileInputStream(certificateFile);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate)certificateFactory.generateCertificate(inputStream2);
inputStream2.close();
//pull out the public key part of the certificate into a KeySpec
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(certificate.getPublicKey().getEncoded());
//generate public key to validate signatures
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
//create credentials
BasicX509Credential publicCredential = new BasicX509Credential();
//add public key value
publicCredential.setPublicKey(publicKey);
//create SignatureValidator
SignatureValidator signatureValidator = new SignatureValidator(publicCredential);
//try to validate
try
{
signatureValidator.validate(signature);
}
catch (ValidationException ve)
{
System.out.println("Signature is NOT valid.");
System.out.println(ve.getMessage());
return;
}
//no validation exception was thrown
System.out.println("Signature is valid.");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
This code if i run this in eclipse it says that the signature is valid. But if I run in RAD8.2 it says signature is invalid. Please help me with this. I am using different workspaces in rad and eclipse
I would like to create x.509 certificate,
so I copy the following codes from Wrox, Beggining Cryptography with Java, chapter 6.
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
import chapter6.PKCS10ExtensionExample;
import chapter6.X509V1CreateExample;
//example of a basic CA
public class PKCS10CertCreateExample
{
public static X509Certificate[] buildChain() throws Exception
{
//create the certification request
KeyPair pair = chapter7.Utils.generateRSAKeyPair();
PKCS10CertificationRequest request = PKCS10ExtensionExample.generateRequest(pair);
//create a root certificate
KeyPair rootPair=chapter7.Utils.generateRSAKeyPair();
X509Certificate rootCert = X509V1CreateExample.generateV1Certificate(rootPair);
//validate the certification request
if(!request.verify("BC"))
{
System.out.println("request failed to verify!");
System.exit(1);
}
//create the certificate using the information in the request
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(rootCert.getSubjectX500Principal());
certGen.setNotBefore(new Date(System.currentTimeMillis()));
certGen.setNotAfter(new Date(System.currentTimeMillis()+50000));
certGen.setSubjectDN(request.getCertificationRequestInfo().getSubject());
certGen.setPublicKey(request.getPublicKey("BC"));
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(rootCert));
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(request.getPublicKey("BC")));
certGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false));
certGen.addExtension(X509Extensions.KeyUsage, true, new BasicConstraints(false));
certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
certGen.addExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));
//extract the extension request attribute
ASN1Set attributes = request.getCertificationRequestInfo().getAttributes();
for(int i=0;i!=attributes.size();i++)
{
Attribute attr = Attribute.getInstance(attributes.getObjectAt(i));
//process extension request
if(attr.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest))
{
X509Extensions extensions = X509Extensions.getInstance(attr.getAttrValues().getObjectAt(0));
Enumeration<?> e = extensions.oids();
while(e.hasMoreElements())
{
DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
X509Extension ext = extensions.getExtension(oid);
certGen.addExtension(oid, ext.isCritical(), ext.getValue().getOctets());
}
}
}
X509Certificate issuedCert = certGen.generateX509Certificate(rootPair.getPrivate());
return new X509Certificate[]{issuedCert, rootCert};
}
public static void main(String[] args) throws Exception
{
X509Certificate[] chain = buildChain();
PEMWriter pemWrt = new PEMWriter(new OutputStreamWriter(System.out));
pemWrt.writeObject(chain[0]);
pemWrt.writeObject(chain[1]);
pemWrt.close();
}
}
However, the codes shows errors as follows
Exception in thread "main" java.lang.IllegalArgumentException: extension 2.5.29.15 already added
at org.bouncycastle.asn1.x509.X509ExtensionsGenerator.addExtension(Unknown Source)
at org.bouncycastle.asn1.x509.X509ExtensionsGenerator.addExtension(Unknown Source)
at org.bouncycastle.x509.X509V3CertificateGenerator.addExtension(Unknown Source)
at PKCS10CertCreateExample.buildChain(PKCS10CertCreateExample.java:68)
at PKCS10CertCreateExample.main(PKCS10CertCreateExample.java:100)
please, help me..
Googling extension 2.5.29.15 will tell you that refers to KeyUsage
Googling the source code for X509V3CertificateGenerator shows that addExtension() calls X509ExtensionsGenerator.addExtension() which throws an exception if the extension provided has already been added.
The source code you provide above does just that, and the exception is thrown:
certGen.addExtension(X509Extensions.KeyUsage, true, new BasicConstraints(false));
certGen.addExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment));
This is a bug in the code. You need to remove one of them. I would guess the first.
I want to sign a text file (may be a .exe file or something else in the future)
using PKCS#7 and verify the signature using Java.
What do I need to know?
Where will I find an API (.jar and documentation)?
What are the steps I need to follow in order to sign data and verify the data?
Please provide me code snippet if possible.
I reckon you need the following 2 Bouncy Castle jars to generate the PKCS7 digital signature:
bcprov-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
bcmail-jdk15on-147.jar (for JDK 1.5 - JDK 1.7)
You can download the Bouncy Castle jars from here.
You need to setup your keystore with the public & private key pair.
You need only the private key to generate the digital signature & the public key to verify it.
Here's how you'd pkcs7 sign content (Exception handling omitted for brevity) :
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Base64;
public final class PKCS7Signer {
private static final String PATH_TO_KEYSTORE = "/path/to/keyStore";
private static final String KEY_ALIAS_IN_KEYSTORE = "My_Private_Key";
private static final String KEYSTORE_PASSWORD = "MyPassword";
private static final String SIGNATUREALGO = "SHA1withRSA";
public PKCS7Signer() {
}
KeyStore loadKeyStore() throws Exception {
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream(PATH_TO_KEYSTORE);
keystore.load(is, KEYSTORE_PASSWORD.toCharArray());
return keystore;
}
CMSSignedDataGenerator setUpProvider(final KeyStore keystore) throws Exception {
Security.addProvider(new BouncyCastleProvider());
Certificate[] certchain = (Certificate[]) keystore.getCertificateChain(KEY_ALIAS_IN_KEYSTORE);
final List<Certificate> certlist = new ArrayList<Certificate>();
for (int i = 0, length = certchain == null ? 0 : certchain.length; i < length; i++) {
certlist.add(certchain[i]);
}
Store certstore = new JcaCertStore(certlist);
Certificate cert = keystore.getCertificate(KEY_ALIAS_IN_KEYSTORE);
ContentSigner signer = new JcaContentSignerBuilder(SIGNATUREALGO).setProvider("BC").
build((PrivateKey) (keystore.getKey(KEY_ALIAS_IN_KEYSTORE, KEYSTORE_PASSWORD.toCharArray())));
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").
build()).build(signer, (X509Certificate) cert));
generator.addCertificates(certstore);
return generator;
}
byte[] signPkcs7(final byte[] content, final CMSSignedDataGenerator generator) throws Exception {
CMSTypedData cmsdata = new CMSProcessableByteArray(content);
CMSSignedData signeddata = generator.generate(cmsdata, true);
return signeddata.getEncoded();
}
public static void main(String[] args) throws Exception {
PKCS7Signer signer = new PKCS7Signer();
KeyStore keyStore = signer.loadKeyStore();
CMSSignedDataGenerator signatureGenerator = signer.setUpProvider(keyStore);
String content = "some bytes to be signed";
byte[] signedBytes = signer.signPkcs7(content.getBytes("UTF-8"), signatureGenerator);
System.out.println("Signed Encoded Bytes: " + new String(Base64.encode(signedBytes)));
}
}
PKCS#7 is known as CMS now (Cryptographic Message Syntax), and you will need the Bouncy Castle PKIX libraries to create one. It has ample documentation and a well established mailing list.
I won't supply code snippet, it is against house rules. Try yourself first.