Introduction
The Java Keytool project has most of the code to create x509 certificates in java, but it has dependency to sun class, which are deprecated, which means that they can change. So be carefully to test this code for different JRE before going into production.
How to Create a X509 Certificate in Java without BouncyCastle?
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import sun.security.util.ObjectIdentifier;
import sun.security.x509.AccessDescription;
import sun.security.x509.AlgorithmId;
import sun.security.x509.AuthorityInfoAccessExtension;
import sun.security.x509.AuthorityKeyIdentifierExtension;
import sun.security.x509.BasicConstraintsExtension;
import sun.security.x509.CRLDistributionPointsExtension;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateExtensions;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.DNSName;
import sun.security.x509.DistributionPoint;
import sun.security.x509.ExtendedKeyUsageExtension;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNames;
import sun.security.x509.KeyIdentifier;
import sun.security.x509.KeyUsageExtension;
import sun.security.x509.SerialNumber;
import sun.security.x509.SubjectAlternativeNameExtension;
import sun.security.x509.SubjectKeyIdentifierExtension;
import sun.security.x509.URIName;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
@SuppressWarnings("restriction")
public class X509CertificateTest {
public X509Certificate createX509Certificate(X500Name subject, X500Name issuer, Date validityFrom, Date validityTo,
PublicKey publicKey, PrivateKey signingPrivateKey, PublicKey signingPublicKey, String algorithm)
throws CertificateException, IOException, InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, SignatureException {
X509CertInfo info = new X509CertInfo();
info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(1));
info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get(algorithm)));
info.set(X509CertInfo.SUBJECT, subject);
info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));
info.set(X509CertInfo.VALIDITY, new CertificateValidity(validityFrom, validityTo));
info.set(X509CertInfo.ISSUER, issuer);
// X509v3 extensions
CertificateExtensions exts = new CertificateExtensions();
// Extensions[1]: Authority Information Access
List<AccessDescription> accDescr = new ArrayList<>();
String urlCA = "http://magnuskkarlsson.se/ca.cer";
String urlOCSP = "http://magnuskkarlsson.se/ocsp";
accDescr.add(new AccessDescription(AccessDescription.Ad_CAISSUERS_Id, new GeneralName(new URIName(urlCA))));
accDescr.add(new AccessDescription(AccessDescription.Ad_OCSP_Id, new GeneralName(new URIName(urlOCSP))));
exts.set(AuthorityInfoAccessExtension.NAME, new AuthorityInfoAccessExtension(accDescr));
// Extensions[2]: X509v3 Authority Key Identifier
exts.set(AuthorityKeyIdentifierExtension.NAME,
new AuthorityKeyIdentifierExtension(new KeyIdentifier(signingPublicKey),
new GeneralNames().add(new GeneralName(subject)), new SerialNumber(1)));
// Extensions[3]: X509v3 Basic Constraints: critical=true, ca=false, pathLen=-1=undefined
exts.set(BasicConstraintsExtension.NAME, new BasicConstraintsExtension(true, false, -1));
// Extensions[4]: X509v3 CRL Distribution Points
List<DistributionPoint> cdp = new ArrayList<>();
String urlCRL = "http://magnuskkarlsson.se/ca.crl";
cdp.add(new DistributionPoint(new GeneralNames().add(new GeneralName(new URIName(urlCRL))), null, null));
exts.set(CRLDistributionPointsExtension.NAME, new CRLDistributionPointsExtension(cdp));
// Extensions[5]: X509v3 Extended Key Usage
Vector<ObjectIdentifier> keyUsages = new Vector<>();
// OID defined in RFC 3280 Sections 4.2.1.13
// more from http://www.alvestrand.no/objectid/1.3.6.1.5.5.7.3.html
// serverAuth
keyUsages.addElement(ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 3, 1 }));
// clientAuth
keyUsages.addElement(ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 3, 2 }));
exts.set(ExtendedKeyUsageExtension.NAME, new ExtendedKeyUsageExtension(keyUsages));
// Extensions[6]: X509v3 Key Usage
KeyUsageExtension keyUsage = new KeyUsageExtension();
keyUsage.set(KeyUsageExtension.DIGITAL_SIGNATURE, Boolean.TRUE);
keyUsage.set(KeyUsageExtension.NON_REPUDIATION, Boolean.FALSE);
keyUsage.set(KeyUsageExtension.KEY_ENCIPHERMENT, Boolean.TRUE);
keyUsage.set(KeyUsageExtension.DATA_ENCIPHERMENT, Boolean.FALSE);
keyUsage.set(KeyUsageExtension.KEY_AGREEMENT, Boolean.FALSE);
keyUsage.set(KeyUsageExtension.KEY_CERTSIGN, Boolean.FALSE);
keyUsage.set(KeyUsageExtension.CRL_SIGN, Boolean.FALSE);
keyUsage.set(KeyUsageExtension.ENCIPHER_ONLY, Boolean.FALSE);
keyUsage.set(KeyUsageExtension.DECIPHER_ONLY, Boolean.FALSE);
exts.set(KeyUsageExtension.NAME, keyUsage);
// Extensions[7]: Subject Alternative Name
String urlSAN = "magnuskkarlsson.com";
exts.set(SubjectAlternativeNameExtension.NAME,
new SubjectAlternativeNameExtension(new GeneralNames().add(new GeneralName(new DNSName(urlSAN)))));
// Extensions[8]: X509v3 Subject Key Identifier
exts.set(SubjectKeyIdentifierExtension.NAME,
new SubjectKeyIdentifierExtension(new KeyIdentifier(publicKey).getIdentifier()));
info.set(X509CertInfo.EXTENSIONS, exts);
// Sign the certificate with the CA private key
X509CertImpl cert = new X509CertImpl(info);
cert.sign(signingPrivateKey, algorithm);
return cert;
}
public X500Name createX500Name(String commonName, String organizationUnit, String organizationName,
String localityName, String stateName, String country) throws IOException {
return new X500Name(commonName, organizationUnit, organizationName, localityName, stateName, country);
}
public Date[] createValidity(int days) {
Date from = new Date();
Date to = new Date(from.getTime() + days * 86400000l);
return new Date[] { from, to };
}
public KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048, new SecureRandom());
return keyGen.generateKeyPair();
}
public static void main(String[] args) throws Exception {
// CertificateFactory factory = CertificateFactory.getInstance("X.509");
// InputStream input = ClassLoader.getSystemResourceAsStream("server-v3.cert.pem");
// X509Certificate certDemo = (X509Certificate) factory.generateCertificate(input);
// System.out.println(certDemo);
X509CertificateTest test = new X509CertificateTest();
X500Name subject = test.createX500Name("localhost", "Purch", "Onizuka, Inc.", "Palo Alto", "California", "CH");
Date[] validity = test.createValidity(730);
KeyPair keyPair = test.generateKeyPair();
X509Certificate cert = test.createX509Certificate(subject, subject, validity[0], validity[1],
keyPair.getPublic(), keyPair.getPrivate(), keyPair.getPublic(), "SHA256withRSA");
System.out.println(cert);
}
}
And when run
[
[
Version: V3
Subject: CN=localhost, OU=Purch, O="Onizuka, Inc.", L=Palo Alto, ST=California, C=CH
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus: 16430622413258256674241974707951685615738697152316908673861521954949249341917487321969963974880523193055015435475912265313655167640567326771003684773855144686669652477201074611376490251544635379047537527674776936600766762870067059060115972142637033253593758480242365775073879800299177911290829460272374213329378851325135207593915369295651052987402058272708938961270470497580241134442791917877474961958209709747980260907545128710289887887982830065299918209286621365319016851187102417429903048397749408363510478403654647568673004684653502196209388803336825940342089023016860111125056634847644257184487730090507480997167
public exponent: 65537
Validity: [From: Wed May 30 13:38:49 CEST 2018,
To: Fri May 29 13:38:49 CEST 2020]
Issuer: CN=localhost, OU=Purch, O="Onizuka, Inc.", L=Palo Alto, ST=California, C=CH
SerialNumber: [ 01]
Certificate Extensions: 8
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
[
accessMethod: caIssuers
accessLocation: URIName: http://magnuskkarlsson.se/ca.cer
,
accessMethod: ocsp
accessLocation: URIName: http://magnuskkarlsson.se/ocsp
]
]
[2]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 18 B5 68 3F 35 5A 1B 48 5F 9F B3 C3 3E AB E3 CA ..h?5Z.H_...>...
0010: 83 FB 9E 47 ...G
]
[CN=localhost, OU=Purch, O="Onizuka, Inc.", L=Palo Alto, ST=California, C=CH]
SerialNumber: [ 01]
]
[3]: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
CA:false
PathLen: undefined
]
[4]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
[DistributionPoint:
[URIName: http://magnuskkarlsson.se/ca.crl]
]]
[5]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
serverAuth
clientAuth
]
[6]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
DigitalSignature
Key_Encipherment
]
[7]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: magnuskkarlsson.com
]
[8]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 18 B5 68 3F 35 5A 1B 48 5F 9F B3 C3 3E AB E3 CA ..h?5Z.H_...>...
0010: 83 FB 9E 47 ...G
]
]
]
Algorithm: [SHA256withRSA]
Signature:
0000: 58 62 47 8E 55 6B 17 15 37 E9 E9 C3 2B E0 9A 71 XbG.Uk..7...+..q
0010: 11 29 04 F3 39 4E 87 DB 5B 12 73 79 2D 66 76 B3 .)..9N..[.sy-fv.
0020: E0 DD 4A F3 09 39 DF 5A 54 68 69 A7 18 44 F7 39 ..J..9.ZThi..D.9
0030: 21 02 52 6C 1B A8 87 F6 28 BD F7 B2 86 08 43 8C !.Rl....(.....C.
0040: 62 E1 10 EB 7E 3B FB 4D 5B F3 B8 93 F9 EC 67 13 b....;.M[.....g.
0050: 11 EB 99 88 DC CA 8D 48 83 9B 4B B7 6C 4C 7E 99 .......H..K.lL..
0060: C7 9B 16 69 9E EF 20 A0 5D 55 09 EF 75 99 87 5A ...i.. .]U..u..Z
0070: 33 26 56 E1 33 EB A7 83 54 9F 1B 4A 49 02 1E F8 3&V.3...T..JI...
0080: 95 91 99 C3 48 D2 1A C3 3A 3A 8F 99 61 77 7D 7F ....H...::..aw..
0090: D2 0A 85 DA 86 F6 DD 06 32 D0 8D 8D 8E 76 AA 16 ........2....v..
00A0: 19 71 79 3A C1 2A 57 DD E9 C4 AD 48 CB 87 29 EF .qy:.*W....H..).
00B0: 13 99 BA 9E 8A 3F 2E 0C 64 22 3E 66 B3 A7 2C 69 .....?..d">f..,i
00C0: E4 94 63 BB 89 CF 98 45 DE 89 25 5C 0F 1E F1 44 ..c....E..%\...D
00D0: 99 B2 A9 9A 73 64 20 F6 B1 55 EE B7 4C 68 96 F3 ....sd ..U..Lh..
00E0: 84 47 C1 D6 F8 FB 76 11 44 71 43 01 72 F5 A0 C2 .G....v.DqC.r...
00F0: F1 86 F0 FC 6D 9D 05 4A BB 0A 88 C7 ED 4B 5A 4B ....m..J.....KZK
]
No comments:
Post a Comment