Hello I am using the class X509V1CertificateGenerator to generate a certificate of the type X509Certificate.
now the class X509V1CertificateGenerator is deprecated and the recommanded alternative is X509v1CertificateBuilder but I do not know how to do the Migration.
Here is the Code:
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
// set the necessary X500-fields
X500Principal dnName = new X500Principal("CN=MyServerName");
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(dnName);
// expire-date
Calendar expireDate = Calendar.getInstance();
certGen.setNotBefore(expireDate.getTime());
// expires in 25 years
expireDate.add(Calendar.YEAR, 25);
certGen.setNotAfter(expireDate.getTime());
certGen.setSubjectDN(dnName); // note: same as issuer
certGen.setPublicKey(pair.getPublic());
// set the right signature-algorithm ->RSA/DSA
if (this.algorithm)
certGen.setSignatureAlgorithm("MD5withRSA");
else
certGen.setSignatureAlgorithm("SHA1withDSA");
// generate the X509-certificate
X509Certificate cert = certGen.generate(pair.getPrivate(), "BC");
What should I do to do the Migration?
Try this extracted from keycloak CertificateUtils
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded());
X509v1CertificateBuilder builder = new X509v1CertificateBuilder(
subjectDN,
serialNumber,
validityStartDate,
validityEndDate,
subjectDN,
subPubKeyInfo);
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
ContentSigner contentSigner =
new BcRSAContentSignerBuilder(sigAlgId, digAlgId)
.build(PrivateKeyFactory.createKey(pair.getPrivate().getEncoded()));
X509CertificateHolder holder = builder.build(contentSigner);
X509Certificate cert = JcaX509CertificateConverter().getCertificate(holder);
Related
I'm trying to store a private key in the android keystore but i keep getting an error, what am i doing wrong here ? I'm self signing the certificate because i need one to store the key but i don't need it.
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
keyPairGen.initialize(1280);
KeyPair pair = keyPairGen.generateKeyPair();
PrivateKey privKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
Certificate certificate = selfSign(pair, "myCer");
KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
ks.setKeyEntry("MyPrivateKey", privKey, null, new Certificate[] { certificate });
Self signed certificate method :
public final static Certificate selfSign(KeyPair keyPair, String subjectDN) throws OperatorCreationException, CertificateException, IOException, CertIOException, CertificateException {
Provider bcProvider = new BouncyCastleProvider();
Security.addProvider(bcProvider);
long now = System.currentTimeMillis();
Date startDate = new Date(now);
X500Name dnName = new X500Name("CN=" + subjectDN);
BigInteger certSerialNumber = new BigInteger(Long.toString(now)); // <-- Using the current timestamp as the certificate serial number
Calendar calendar = Calendar.getInstance();
calendar.setTime(startDate);
calendar.add(Calendar.YEAR, 2); // <-- 1 Yr validity
Date endDate = calendar.getTime();
String signatureAlgorithm = "SHA256WithRSA"; // <-- Use appropriate signature algorithm based on your keyPair algorithm.
ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, keyPair.getPublic());
// Extensions --------------------------
// Basic Constraints
BasicConstraints basicConstraints = new BasicConstraints(true); // <-- true for CA, false for EndEntity
certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, basicConstraints); // Basic Constraints is usually marked as critical.
// -------------------------------------
return new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(contentSigner));
}
I have a Root CA certificate that has to sign a certificate that I am creating.
public static X509Certificate generateCertificate(final PublicKey publicKey,
final PrivateKey privateKey,
final String signingAlgorithm, GeneralNames names)
throws IOException, CertificateException, OperatorCreationException, NoSuchAlgorithmException
{
final X500NameBuilder subject = new X500NameBuilder(RFC4519Style.INSTANCE);
subject.addRDN(BCStyle.C, COUNTRY_NAME);
subject.addRDN(BCStyle.ST, STATE_NAME);
subject.addRDN(BCStyle.L, LOCALITY_NAME);
subject.addRDN(BCStyle.O, ORGANIZATION_NAME);
subject.addRDN(BCStyle.OU, ORGANIZATION_UNIT_NAME);
subject.addRDN(BCStyle.E, EMAIL_ADDRESS);
final X500NameBuilder issuer = new X500NameBuilder(RFC4519Style.INSTANCE);
issuer.addRDN(BCStyle.C, COUNTRY_NAME);
issuer.addRDN(BCStyle.ST, STATE_NAME);
issuer.addRDN(BCStyle.L, LOCALITY_NAME);
issuer.addRDN(BCStyle.O, ORGANIZATION_NAME);
issuer.addRDN(BCStyle.OU, ISSUER);
final BigInteger sn = new BigInteger(SERIAL_NUMBER_LENGTH, new SecureRandom());
final Date validFrom = Calendar.getInstance().getTime();
final Calendar c = Calendar.getInstance();
c.add(Calendar.YEAR, YEARS_VALID);
final Date validUntil = c.getTime();
File file = new File("PATH TO ROOT CA");
CertificateFactory fact = CertificateFactory.getInstance("X.509");
FileInputStream in = new FileInputStream(file);
X509Certificate cer = (X509Certificate) fact.generateCertificate(in);
final JcaContentSignerBuilder builder = new JcaContentSignerBuilder(signingAlgorithm);
ContentSigner signer = builder.build(privateKey);
final X509v3CertificateBuilder certBuilder=new JcaX509v3CertificateBuilder(cer, sn, validFrom, validUntil, subject.build(), publicKey);
BasicConstraints constr = new BasicConstraints(false);
KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.nonRepudiation | KeyUsage.keyEncipherment);
certBuilder.addExtension(Extension.keyUsage, false, usage);
certBuilder.addExtension(Extension.subjectAlternativeName, false, names);
certBuilder.addExtension(Extension.basicConstraints, false, constr);
// certBuilder.addExtension(Extension.authorityKeyIdentifier, false,utiles.createAuthorityKeyIdentifier(cer));
certBuilder.addExtension(Extension.subjectKeyIdentifier, false,
new SubjectKeyIdentifier(publicKey.getEncoded()));
final byte[] certBytes = certBuilder.build(signer).getEncoded();
final CertificateFactory certificateFactory = CertificateFactory.getInstance(CERTIFICATE_TYPE);
return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes));
}
I have tried a number of things but I can't find exactly a solution. Also I don't understand what i have to set on Subject Key Identifier extension.
It seems you're not getting the X.509 certificate generation process right:
You generate a Certificate Signing Request (CSR), which is basically your certificate's structure, not yet signed by a CA;
A Certificate Authority (in this case, your root CA) signs this CSR.
Have a look at Sign CSR using Bouncy Castle, which is probably what you're looking for.
I use the code published at https://github.com/jscep/jscep
In response to client.enrol I get :
InvalidContentTypeException: Expected [application/x-x509-ca-cert, application/x-x509-ca-ra-cert], but was null
URL url = new URL("http://212.29.229.154/certsrv/mscep/mscep.dll");
// Default Callback Mechanism
CertificateVerifier verifier = new ConsoleCertificateVerifier();
CallbackHandler handler = new DefaultCallbackHandler(verifier);
// Creating the Client
Client client = new Client(url, handler);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair requesterKeyPair = keyGen.genKeyPair();
Capabilities caps = client.getCaCapabilities();
String sigAlg = caps.getStrongestSignatureAlgorithm();
X500Principal requesterIssuer = new X500Principal("CN=jscep.org, L=Netanya, ST=Sharon, C=IL");
BigInteger serial = BigInteger.ONE;
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, -1); // yesterday
Date notBefore = calendar.getTime();
calendar.add(Calendar.DATE, +2); // tomorrow
Date notAfter = calendar.getTime();
X500Principal requesterSubject = new X500Principal("CN=jscep.org, L=Netanya, ST=Sharon, C=IL"); // doesn't need to be the same as issuer
PublicKey requesterPubKey = requesterKeyPair.getPublic(); // from generated key pair
JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(requesterIssuer, serial, notBefore, notAfter, requesterSubject, requesterPubKey);
// Optional extensions
// certBuilder.addExtension(X509Extension.keyUsage, false, new KeyUsage(KeyUsage.digitalSignature));
// Signing
PrivateKey requesterPrivKey = requesterKeyPair.getPrivate(); // from generated key pair
JcaContentSignerBuilder certSignerBuilder = new JcaContentSignerBuilder(sigAlg); // from above
ContentSigner certSigner = certSignerBuilder.build(requesterPrivKey);
X509CertificateHolder certHolder = certBuilder.build(certSigner);
JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
X509Certificate requesterCert = converter.getCertificate(certHolder);
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair entityKeyPair = keyPairGenerator.genKeyPair();
X500Principal entitySubject = requesterSubject; // use the same subject as the self-signed certificate
PublicKey entityPubKey = entityKeyPair.getPublic();
PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(entitySubject, entityPubKey);
DERPrintableString password = new DERPrintableString("password");
csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_challengePassword, password);
PrivateKey entityPrivKey = entityKeyPair.getPrivate();
JcaContentSignerBuilder csrSignerBuilder = new JcaContentSignerBuilder("SHA1withRSA");
ContentSigner csrSigner = csrSignerBuilder.build(entityPrivKey);
PKCS10CertificationRequest csr = csrBuilder.build(csrSigner);
EnrollmentResponse res = client.enrol(requesterCert, requesterPrivKey, csr);
Is this the way to add the signing certificate as signed attribute?
JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
Attribute attr = new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString( this.digest(myCert.getEncoded()) )));// using SHA-512 for this.digest()
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
builder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
On verification
signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))
I got exception:
org.bouncycastle.cms.CMSSignerDigestMismatchException: message-digest attribute value does not match calculated value
For digest calculation of the attribute I use SHA-512, for signing SHA512withRSA.
The signing certificate can be added as signed attribute using BouncyCastle as:
final X500Name issuerX500Name = new X509CertificateHolder(mycert.getEncoded()).getIssuer();
final GeneralName generalName = new GeneralName(issuerX500Name);
final GeneralNames generalNames = new GeneralNames(generalName);
final BigInteger serialNumber = mycert.getSerialNumber();
final IssuerSerial issuerSerial = new IssuerSerial(generalNames, serialNumber);
ESSCertIDv2 certid = new ESSCertIDv2(new AlgorithmIdentifier(new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.3")), this.digest(mycert.getEncoded()), issuerSerial);
SigningCertificateV2 sigcert = new SigningCertificateV2(certid);
final DERSet attrValues = new DERSet(sigcert);
Attribute attr = new Attribute(PKCSObjectIdentifiers.id_aa_signingCertificateV2, attrValues);
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(attr);
JcaSignerInfoGeneratorBuilder builder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
builder.setSignedAttributeGenerator(new DefaultSignedAttributeTableGenerator(new AttributeTable(v)));
When I use the openssl command to create a certificate, it has the option to secure the private key with a password. However, when I programmatically create a certificate and public/private key pair in Java, the Java API only has a way to set a password on the keystone but not on the private key (unlike the openssl command). So is there no way to encrypt the private key with a password like in the openssl command?
If it helps, here's how I'm creating the private key and certificate in Java:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
X509CertInfo info = new X509CertInfo();
CertificateValidity validityInterval = generateValidityInterval();
BigInteger serialNumber = new BigInteger(SERIAL_NUMBER_SIZE, new SecureRandom());
X500Name owner = new X500Name(DN);
info.set(X509CertInfo.VALIDITY, validityInterval);
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serialNumber));
info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
AlgorithmId certificateAlgorithm = new AlgorithmId(CERTIFICATE_ALGORITHM);
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(certificateAlgorithm));
X509CertImpl certificate = new X509CertImpl(info);
certificate.sign(keyPair.getPrivate(), new AlgorithmId(SIGNATURE_ALGORITHM).getName());
AlgorithmId x509Algorithm = (AlgorithmId) certificate.get(X509CertImpl.SIG_ALG);
info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, x509Algorithm);
certificate = new X509CertImpl(info);
certificate.sign(keyPair.getPrivate(), new AlgorithmId(SIGNATURE_ALGORITHM).getName());