-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added changes for self signed cert generation
- Loading branch information
1 parent
821215f
commit f06b3db
Showing
3 changed files
with
246 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
173 changes: 173 additions & 0 deletions
173
karate-core/src/main/java/com/intuit/karate/http/cert/SelfSignedCertGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
package com.intuit.karate.http.cert; | ||
|
||
import com.intuit.karate.Logger; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.asn1.x500.X500Name; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.cert.X509CertificateHolder; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.cert.X509v3CertificateBuilder; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.cert.jcajce.JcaX509CertificateConverter; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.operator.ContentSigner; | ||
import com.linecorp.armeria.internal.shaded.bouncycastle.operator.jcajce.JcaContentSignerBuilder; | ||
import io.netty.buffer.ByteBuf; | ||
import io.netty.buffer.Unpooled; | ||
import io.netty.handler.codec.base64.Base64; | ||
import io.netty.util.CharsetUtil; | ||
import io.netty.util.internal.PlatformDependent; | ||
import io.netty.util.internal.SystemPropertyUtil; | ||
import io.netty.util.internal.ThrowableUtil; | ||
|
||
import java.io.*; | ||
import java.math.BigInteger; | ||
import java.security.*; | ||
import java.security.cert.CertificateEncodingException; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.CertificateFactory; | ||
import java.security.cert.X509Certificate; | ||
import java.util.Date; | ||
|
||
public final class SelfSignedCertGenerator { | ||
private static final Logger logger = new Logger(); | ||
private static final Provider PROVIDER = Security.getProvider("SUN"); | ||
private static final String DEFAULT_FQDN = "localhost"; | ||
private static final Date DEFAULT_NOT_BEFORE = new Date(SystemPropertyUtil.getLong("io.netty.selfSignedCertificate.defaultNotBefore", System.currentTimeMillis() - 31536000000L)); | ||
private static final Date DEFAULT_NOT_AFTER = new Date(SystemPropertyUtil.getLong("io.netty.selfSignedCertificate.defaultNotAfter", 253402300799000L)); | ||
private static final String ALGORITHM = "RSA"; | ||
private static final int DEFAULT_KEY_LENGTH_BITS = SystemPropertyUtil.getInt("io.netty.handler.ssl.util.selfSignedKeyStrength", 2048); | ||
|
||
private File certificate; | ||
private File privateKey; | ||
private X509Certificate cert; | ||
private PrivateKey key; | ||
|
||
public SelfSignedCertGenerator() throws CertificateException { | ||
KeyPair keypair; | ||
SecureRandom random = ThreadLocalInsecureRandom.current(); | ||
try { | ||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM); | ||
keyGen.initialize(DEFAULT_KEY_LENGTH_BITS, random); | ||
keypair = keyGen.generateKeyPair(); | ||
} catch (NoSuchAlgorithmException var24) { | ||
throw new Error(var24); | ||
} | ||
|
||
String[] paths; | ||
try { | ||
paths = generate(DEFAULT_FQDN, keypair, random, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER); | ||
} catch (Throwable var23) { | ||
logger.debug("Failed to generate a self-signed X.509 certificate:", var23); | ||
CertificateException certificateException = new CertificateException("No provider succeeded to generate a self-signed certificate. See debug log for the root cause.", var23); | ||
ThrowableUtil.addSuppressed(certificateException, var23); | ||
throw certificateException; | ||
} | ||
|
||
this.certificate = new File(paths[0]); | ||
this.privateKey = new File(paths[1]); | ||
this.key = keypair.getPrivate(); | ||
FileInputStream certificateInput = null; | ||
|
||
try { | ||
certificateInput = new FileInputStream(this.certificate); | ||
this.cert = (X509Certificate) CertificateFactory.getInstance("X509").generateCertificate(certificateInput); | ||
} catch (Exception var21) { | ||
throw new CertificateEncodingException(var21); | ||
} finally { | ||
if (certificateInput != null) { | ||
try { | ||
certificateInput.close(); | ||
} catch (IOException var25) { | ||
logger.warn("Failed to close a file: " + this.certificate, var25); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public File getCertificate() { | ||
return certificate; | ||
} | ||
|
||
public File getPrivateKey() { | ||
return privateKey; | ||
} | ||
|
||
private String[] generate(String fqdn, KeyPair keypair, SecureRandom random, Date notBefore, Date notAfter) throws Exception { | ||
PrivateKey key = keypair.getPrivate(); | ||
X500Name owner = new X500Name("CN=" + fqdn); | ||
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(owner, new BigInteger(64, random), notBefore, notAfter, owner, keypair.getPublic()); | ||
ContentSigner signer = (new JcaContentSignerBuilder("SHA256WithRSAEncryption")).build(key); | ||
X509CertificateHolder certHolder = builder.build(signer); | ||
X509Certificate cert = new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certHolder); | ||
cert.verify(keypair.getPublic()); | ||
return newSelfSignedCertificate(fqdn, key, cert); | ||
} | ||
|
||
private String[] newSelfSignedCertificate(String fqdn, PrivateKey key, X509Certificate cert) throws IOException, CertificateEncodingException { | ||
ByteBuf wrappedBuf = Unpooled.wrappedBuffer(key.getEncoded()); | ||
ByteBuf encodedBuf; | ||
String keyText; | ||
try { | ||
encodedBuf = Base64.encode(wrappedBuf, true); | ||
try { | ||
keyText = "-----BEGIN PRIVATE KEY-----\n" + encodedBuf.toString(CharsetUtil.US_ASCII) + "\n-----END PRIVATE KEY-----\n"; | ||
} finally { | ||
encodedBuf.release(); | ||
} | ||
} finally { | ||
wrappedBuf.release(); | ||
} | ||
fqdn = fqdn.replaceAll("[^\\w.-]", "x"); | ||
File keyFile = PlatformDependent.createTempFile("keyutil_" + fqdn + '_', ".key", (File)null); | ||
keyFile.deleteOnExit(); | ||
OutputStream keyOut = new FileOutputStream(keyFile); | ||
try { | ||
keyOut.write(keyText.getBytes(CharsetUtil.US_ASCII)); | ||
keyOut.close(); | ||
keyOut = null; | ||
} finally { | ||
if (keyOut != null) { | ||
safeClose(keyFile, keyOut); | ||
safeDelete(keyFile); | ||
} | ||
} | ||
wrappedBuf = Unpooled.wrappedBuffer(cert.getEncoded()); | ||
String certText; | ||
try { | ||
encodedBuf = Base64.encode(wrappedBuf, true); | ||
try { | ||
certText = "-----BEGIN CERTIFICATE-----\n" + encodedBuf.toString(CharsetUtil.US_ASCII) + "\n-----END CERTIFICATE-----\n"; | ||
} finally { | ||
encodedBuf.release(); | ||
} | ||
} finally { | ||
wrappedBuf.release(); | ||
} | ||
File certFile = PlatformDependent.createTempFile("keyutil_" + fqdn + '_', ".crt", (File)null); | ||
certFile.deleteOnExit(); | ||
OutputStream certOut = new FileOutputStream(certFile); | ||
try { | ||
certOut.write(certText.getBytes(CharsetUtil.US_ASCII)); | ||
certOut.close(); | ||
certOut = null; | ||
} finally { | ||
if (certOut != null) { | ||
safeClose(certFile, certOut); | ||
safeDelete(certFile); | ||
safeDelete(keyFile); | ||
} | ||
} | ||
return new String[]{certFile.getPath(), keyFile.getPath()}; | ||
} | ||
|
||
private static void safeDelete(File certFile) { | ||
if (!certFile.delete()) { | ||
logger.warn("Failed to delete a file: " + certFile); | ||
} | ||
} | ||
|
||
private static void safeClose(File keyFile, OutputStream keyOut) { | ||
try { | ||
keyOut.close(); | ||
} catch (IOException var3) { | ||
logger.warn("Failed to close a file: " + keyFile, var3); | ||
} | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
karate-core/src/main/java/com/intuit/karate/http/cert/ThreadLocalInsecureRandom.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package com.intuit.karate.http.cert; | ||
|
||
import io.netty.util.internal.PlatformDependent; | ||
import java.security.SecureRandom; | ||
import java.util.Random; | ||
|
||
final class ThreadLocalInsecureRandom extends SecureRandom { | ||
private static final long serialVersionUID = -8209473337192526191L; | ||
private static final SecureRandom INSTANCE = new ThreadLocalInsecureRandom(); | ||
|
||
static SecureRandom current() { | ||
return INSTANCE; | ||
} | ||
|
||
private ThreadLocalInsecureRandom() { | ||
} | ||
|
||
public String getAlgorithm() { | ||
return "insecure"; | ||
} | ||
|
||
public void setSeed(byte[] seed) { | ||
} | ||
|
||
public void setSeed(long seed) { | ||
} | ||
|
||
public void nextBytes(byte[] bytes) { | ||
random().nextBytes(bytes); | ||
} | ||
|
||
public byte[] generateSeed(int numBytes) { | ||
byte[] seed = new byte[numBytes]; | ||
random().nextBytes(seed); | ||
return seed; | ||
} | ||
|
||
public int nextInt() { | ||
return random().nextInt(); | ||
} | ||
|
||
public int nextInt(int n) { | ||
return random().nextInt(n); | ||
} | ||
|
||
public boolean nextBoolean() { | ||
return random().nextBoolean(); | ||
} | ||
|
||
public long nextLong() { | ||
return random().nextLong(); | ||
} | ||
|
||
public float nextFloat() { | ||
return random().nextFloat(); | ||
} | ||
|
||
public double nextDouble() { | ||
return random().nextDouble(); | ||
} | ||
|
||
public double nextGaussian() { | ||
return random().nextGaussian(); | ||
} | ||
|
||
private static Random random() { | ||
return PlatformDependent.threadLocalRandom(); | ||
} | ||
} |