Skip to content

Commit b05a367

Browse files
add ca-keyusage option
1 parent d8c8d30 commit b05a367

File tree

5 files changed

+40
-6
lines changed

5 files changed

+40
-6
lines changed

x-pack/plugin/security/cli/src/main/java/org/elasticsearch/xpack/security/cli/CertGenUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ private CertGenUtils() {}
147147
/**
148148
* Generates a CA certificate
149149
*/
150-
public static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days)
150+
public static X509Certificate generateCACertificate(X500Principal x500Principal, KeyPair keyPair, int days, KeyUsage keyUsage)
151151
throws OperatorCreationException, CertificateException, CertIOException, NoSuchAlgorithmException {
152-
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true, days, null, null, Set.of());
152+
return generateSignedCertificate(x500Principal, null, keyPair, null, null, true, days, null, keyUsage, Set.of());
153153
}
154154

155155
/**

x-pack/plugin/security/cli/src/main/java/org/elasticsearch/xpack/security/cli/CertificateGenerateTool.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ static CAInfo getCAInfo(
403403
// generate the CA keys and cert
404404
X500Principal x500Principal = new X500Principal(dn);
405405
KeyPair keyPair = CertGenUtils.generateKeyPair(keysize);
406-
Certificate caCert = CertGenUtils.generateCACertificate(x500Principal, keyPair, days);
406+
Certificate caCert = CertGenUtils.generateCACertificate(x500Principal, keyPair, days, null);
407407
final char[] password;
408408
if (prompt) {
409409
password = terminal.readSecret("Enter password for CA private key: ");

x-pack/plugin/security/cli/src/main/java/org/elasticsearch/xpack/security/cli/CertificateTool.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.bouncycastle.asn1.DERIA5String;
1616
import org.bouncycastle.asn1.x509.GeneralName;
1717
import org.bouncycastle.asn1.x509.GeneralNames;
18+
import org.bouncycastle.asn1.x509.KeyUsage;
1819
import org.bouncycastle.jce.provider.BouncyCastleProvider;
1920
import org.bouncycastle.openssl.PEMEncryptor;
2021
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
@@ -110,6 +111,7 @@ class CertificateTool extends MultiCommand {
110111
"[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1," + MAX_FILENAME_LENGTH + "}"
111112
);
112113
private static final int DEFAULT_KEY_SIZE = 2048;
114+
static final List<String> DEFAULT_CA_KEY_USAGE = List.of("keyCertSign", "cRLSign");
113115

114116
// Older versions of OpenSSL had a max internal password length.
115117
// We issue warnings when writing files with passwords that would not be usable in those versions of OpenSSL.
@@ -202,6 +204,7 @@ abstract static class CertificateCommand extends EnvironmentAwareCommand {
202204
final OptionSpec<String> outputPathSpec;
203205
final OptionSpec<String> outputPasswordSpec;
204206
final OptionSpec<Integer> keysizeSpec;
207+
OptionSpec<String> caKeyUsageSpec;
205208

206209
OptionSpec<Void> pemFormatSpec;
207210
OptionSpec<Integer> daysSpec;
@@ -247,6 +250,7 @@ final void acceptsCertificateAuthority() {
247250
.withOptionalArg();
248251

249252
acceptsCertificateAuthorityName();
253+
acceptCertificateAuthorityKeyUsage();
250254
}
251255

252256
void acceptsCertificateAuthorityName() {
@@ -274,6 +278,20 @@ final void acceptInputFile() {
274278
inputFileSpec = parser.accepts("in", "file containing details of the instances in yaml format").withRequiredArg();
275279
}
276280

281+
final void acceptCertificateAuthorityKeyUsage() {
282+
OptionSpecBuilder builder = parser.accepts(
283+
"ca-keyusage",
284+
"comma separated key usages to use for the generated CA. defaults to " + DEFAULT_CA_KEY_USAGE
285+
);
286+
if (caPkcs12PathSpec != null) {
287+
builder = builder.availableUnless(caPkcs12PathSpec);
288+
}
289+
if (caCertPathSpec != null) {
290+
builder = builder.availableUnless(caCertPathSpec);
291+
}
292+
caKeyUsageSpec = builder.withRequiredArg();
293+
}
294+
277295
// For testing
278296
OptionParser getParser() {
279297
return parser;
@@ -396,7 +414,16 @@ CAInfo generateCA(Terminal terminal, OptionSet options) throws Exception {
396414
}
397415
X500Principal x500Principal = new X500Principal(dn);
398416
KeyPair keyPair = CertGenUtils.generateKeyPair(getKeySize(options));
399-
X509Certificate caCert = CertGenUtils.generateCACertificate(x500Principal, keyPair, getDays(options));
417+
final Function<String, Stream<? extends String>> splitByComma = v -> Arrays.stream(Strings.splitStringByCommaToArray(v));
418+
final KeyUsage caKeyUsage;
419+
if (options.hasArgument(caKeyUsageSpec)) {
420+
List<String> keyUsageNames = caKeyUsageSpec.values(options).stream().flatMap(splitByComma).toList();
421+
caKeyUsage = CertGenUtils.buildKeyUsage(keyUsageNames);
422+
} else {
423+
caKeyUsage = CertGenUtils.buildKeyUsage(DEFAULT_CA_KEY_USAGE);
424+
}
425+
426+
X509Certificate caCert = CertGenUtils.generateCACertificate(x500Principal, keyPair, getDays(options), caKeyUsage);
400427

401428
if (options.hasArgument(caPasswordSpec)) {
402429
char[] password = getChars(caPasswordSpec.value(options));
@@ -947,6 +974,7 @@ static class CertificateAuthorityCommand extends CertificateCommand {
947974
super("generate a new local certificate authority");
948975
acceptCertificateGenerationOptions();
949976
acceptsCertificateAuthorityName();
977+
acceptCertificateAuthorityKeyUsage();
950978
super.caPasswordSpec = super.outputPasswordSpec;
951979
}
952980

x-pack/plugin/security/cli/src/test/java/org/elasticsearch/xpack/security/cli/CertificateGenerateToolTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public void testGeneratingSignedCertificates() throws Exception {
274274
final int keysize = randomFrom(1024, 2048);
275275
final int days = randomIntBetween(1, 1024);
276276
KeyPair keyPair = CertGenUtils.generateKeyPair(keysize);
277-
X509Certificate caCert = CertGenUtils.generateCACertificate(new X500Principal("CN=test ca"), keyPair, days);
277+
X509Certificate caCert = CertGenUtils.generateCACertificate(new X500Principal("CN=test ca"), keyPair, days, null);
278278

279279
final boolean generatedCa = randomBoolean();
280280
final char[] keyPassword = randomBoolean() ? SecuritySettingsSourceField.TEST_PASSWORD.toCharArray() : null;

x-pack/plugin/security/cli/src/test/java/org/elasticsearch/xpack/security/cli/CertificateToolTests.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,13 @@ public void testGeneratingSignedPemCertificates() throws Exception {
415415
int days = randomIntBetween(1, 1024);
416416

417417
KeyPair keyPair = CertGenUtils.generateKeyPair(keySize);
418-
X509Certificate caCert = CertGenUtils.generateCACertificate(new X500Principal("CN=test ca"), keyPair, days);
418+
List<String> caKeyUsage = randomBoolean() ? null : CertificateTool.DEFAULT_CA_KEY_USAGE;
419+
X509Certificate caCert = CertGenUtils.generateCACertificate(
420+
new X500Principal("CN=test ca"),
421+
keyPair,
422+
days,
423+
CertGenUtils.buildKeyUsage(caKeyUsage)
424+
);
419425

420426
final boolean selfSigned = randomBoolean();
421427
final String keyPassword = randomBoolean() ? SecuritySettingsSourceField.TEST_PASSWORD : null;

0 commit comments

Comments
 (0)