or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mddiagnostics.mdenums-types.mdindex.mdkey-management.mdtrust-management.mdutilities.md

utilities.mddocs/

0

# SSL Utilities

1

2

Comprehensive utility functions for keystore operations, PEM file parsing, certificate handling, SSL-related tasks, and low-level ASN.1/DER parsing with extensive validation and error handling.

3

4

## Capabilities

5

6

### KeyStore Utilities

7

8

Comprehensive utilities for keystore manipulation, type detection, and key/trust manager creation.

9

10

```java { .api }

11

/**

12

* Utility methods for working with KeyStore instances

13

*/

14

public final class KeyStoreUtil {

15

/**

16

* Infers keystore type from file path extension

17

* @param path keystore file path

18

* @return inferred keystore type (JKS, PKCS12, etc.)

19

*/

20

public static String inferKeyStoreType(String path);

21

22

/**

23

* Reads a keystore from file with specified type and password

24

* @param path path to keystore file

25

* @param ksType keystore type (JKS, PKCS12, etc.)

26

* @param password keystore password

27

* @return loaded KeyStore instance

28

* @throws GeneralSecurityException if keystore loading fails

29

* @throws IOException if file reading fails

30

*/

31

public static KeyStore readKeyStore(Path path, String ksType, char[] password)

32

throws GeneralSecurityException, IOException;

33

34

/**

35

* Builds a keystore from certificate chain and private key

36

* @param certificateChain collection of certificates (first should be end entity)

37

* @param privateKey private key corresponding to end entity certificate

38

* @param password password for keystore and private key protection

39

* @return KeyStore containing the certificate chain and private key

40

* @throws GeneralSecurityException if keystore creation fails

41

*/

42

public static KeyStore buildKeyStore(Collection<Certificate> certificateChain,

43

PrivateKey privateKey, char[] password)

44

throws GeneralSecurityException;

45

46

/**

47

* Filters keystore entries based on predicate

48

* @param store original keystore

49

* @param filter predicate to test keystore entries

50

* @return new KeyStore containing only entries that match the filter

51

*/

52

public static KeyStore filter(KeyStore store, Predicate<KeyStoreEntry> filter);

53

54

/**

55

* Builds a truststore from collection of certificates

56

* @param certificates trusted certificates to include

57

* @return KeyStore configured as truststore

58

* @throws GeneralSecurityException if truststore creation fails

59

*/

60

public static KeyStore buildTrustStore(Iterable<Certificate> certificates)

61

throws GeneralSecurityException;

62

63

/**

64

* Builds a truststore with specific type from certificates

65

* @param certificates trusted certificates to include

66

* @param type keystore type for truststore

67

* @return KeyStore of specified type configured as truststore

68

* @throws GeneralSecurityException if truststore creation fails

69

*/

70

public static KeyStore buildTrustStore(Iterable<Certificate> certificates, String type)

71

throws GeneralSecurityException;

72

73

/**

74

* Creates key manager from certificate chain and private key

75

* @param certificateChain certificate chain (end entity first)

76

* @param privateKey private key for end entity certificate

77

* @param password password for key protection

78

* @return configured X509ExtendedKeyManager

79

* @throws GeneralSecurityException if key manager creation fails

80

* @throws IOException if certificate/key processing fails

81

*/

82

public static X509ExtendedKeyManager createKeyManager(Certificate[] certificateChain,

83

PrivateKey privateKey, char[] password)

84

throws GeneralSecurityException, IOException;

85

86

/**

87

* Creates key manager from keystore

88

* @param keyStore keystore containing private keys and certificates

89

* @param password password for private key access

90

* @param algorithm key manager algorithm (e.g., "SunX509", "PKIX")

91

* @return configured X509ExtendedKeyManager

92

* @throws GeneralSecurityException if key manager creation fails

93

*/

94

public static X509ExtendedKeyManager createKeyManager(KeyStore keyStore, char[] password,

95

String algorithm)

96

throws GeneralSecurityException;

97

98

/**

99

* Creates trust manager from truststore

100

* @param trustStore truststore containing trusted certificates (null for JDK defaults)

101

* @param algorithm trust manager algorithm (e.g., "PKIX", "SunX509")

102

* @return configured X509ExtendedTrustManager

103

* @throws NoSuchAlgorithmException if algorithm is not available

104

* @throws KeyStoreException if truststore access fails

105

*/

106

public static X509ExtendedTrustManager createTrustManager(@Nullable KeyStore trustStore,

107

String algorithm)

108

throws NoSuchAlgorithmException, KeyStoreException;

109

110

/**

111

* Creates trust manager from collection of certificates

112

* @param certificates trusted certificates

113

* @return configured X509ExtendedTrustManager

114

* @throws GeneralSecurityException if trust manager creation fails

115

*/

116

public static X509ExtendedTrustManager createTrustManager(Collection<Certificate> certificates)

117

throws GeneralSecurityException;

118

119

/**

120

* Creates stream of keystore entries for processing

121

* @param keyStore keystore to stream

122

* @param exceptionHandler function to handle GeneralSecurityException during streaming

123

* @return Stream of KeyStoreEntry objects

124

*/

125

public static Stream<KeyStoreEntry> stream(KeyStore keyStore,

126

Function<GeneralSecurityException, ? extends RuntimeException> exceptionHandler);

127

}

128

```

129

130

**Usage Examples:**

131

132

```java

133

import org.elasticsearch.common.ssl.KeyStoreUtil;

134

import java.security.KeyStore;

135

import java.security.PrivateKey;

136

import java.security.cert.Certificate;

137

import java.nio.file.Paths;

138

import java.util.Collection;

139

import java.util.List;

140

141

// Infer keystore type

142

String type = KeyStoreUtil.inferKeyStoreType("keystore.p12"); // returns "PKCS12"

143

String jksType = KeyStoreUtil.inferKeyStoreType("keystore.jks"); // returns "JKS"

144

145

// Read keystore from file

146

KeyStore keystore = KeyStoreUtil.readKeyStore(

147

Paths.get("/etc/ssl/keystore.p12"),

148

"PKCS12",

149

"password".toCharArray()

150

);

151

152

// Build keystore from certificates and key

153

Collection<Certificate> certChain = List.of(endEntityCert, intermediateCert);

154

KeyStore builtKeystore = KeyStoreUtil.buildKeyStore(

155

certChain,

156

privateKey,

157

"password".toCharArray()

158

);

159

160

// Filter keystore entries

161

KeyStore filteredKeystore = KeyStoreUtil.filter(keystore, entry ->

162

entry.getAlias().startsWith("server-"));

163

164

// Build truststore from CA certificates

165

KeyStore truststore = KeyStoreUtil.buildTrustStore(caCertificates);

166

167

// Create key manager

168

X509ExtendedKeyManager keyManager = KeyStoreUtil.createKeyManager(

169

certChain.toArray(new Certificate[0]),

170

privateKey,

171

"password".toCharArray()

172

);

173

174

// Create trust manager from certificates

175

X509ExtendedTrustManager trustManager = KeyStoreUtil.createTrustManager(caCertificates);

176

177

// Stream keystore entries

178

KeyStoreUtil.stream(keystore, ex -> new RuntimeException(ex))

179

.filter(entry -> entry.isKeyEntry())

180

.forEach(entry -> {

181

System.out.println("Key alias: " + entry.getAlias());

182

X509Certificate cert = entry.getX509Certificate();

183

System.out.println("Subject: " + cert.getSubjectX500Principal());

184

});

185

```

186

187

### KeyStore Entry Wrapper

188

189

Wrapper class for individual keystore entries providing convenient access methods.

190

191

```java { .api }

192

/**

193

* Wrapper for individual keystore entries

194

*/

195

public static class KeyStoreEntry {

196

/**

197

* Gets the alias of this keystore entry

198

* @return entry alias

199

*/

200

public String getAlias();

201

202

/**

203

* Gets the certificate as X509Certificate

204

* @return X509Certificate or null if not a certificate entry

205

*/

206

public X509Certificate getX509Certificate();

207

208

/**

209

* Checks if this entry contains a private key

210

* @return true if this is a key entry

211

*/

212

public boolean isKeyEntry();

213

214

/**

215

* Gets the private key from this entry

216

* @param password password for private key access

217

* @return PrivateKey or null if not a key entry or wrong password

218

*/

219

public PrivateKey getKey(char[] password);

220

221

/**

222

* Gets the certificate chain for this entry

223

* @return list of certificates in the chain

224

*/

225

public List<? extends X509Certificate> getX509CertificateChain();

226

227

/**

228

* Deletes this entry from the keystore

229

*/

230

public void delete();

231

}

232

```

233

234

### PEM Utilities

235

236

Utilities for parsing PEM formatted certificates and private keys with support for encrypted keys.

237

238

```java { .api }

239

/**

240

* Utilities for parsing PEM formatted certificates and private keys

241

*/

242

public final class PemUtils {

243

/**

244

* Reads private key from PEM file with optional password

245

* @param path path to PEM private key file

246

* @param passwordSupplier supplier for key password (called only if key is encrypted)

247

* @return parsed PrivateKey

248

* @throws IOException if file reading fails

249

* @throws GeneralSecurityException if key parsing fails

250

*/

251

public static PrivateKey readPrivateKey(Path path, Supplier<char[]> passwordSupplier)

252

throws IOException, GeneralSecurityException;

253

254

/**

255

* Parses PKCS#8 PEM formatted private key string

256

* @param pemString PEM formatted private key string

257

* @return parsed PrivateKey

258

* @throws IOException if PEM parsing fails

259

* @throws GeneralSecurityException if key parsing fails

260

*/

261

public static PrivateKey parsePKCS8PemString(String pemString)

262

throws IOException, GeneralSecurityException;

263

264

/**

265

* Reads certificates from multiple PEM files

266

* @param certPaths collection of paths to PEM certificate files

267

* @return list of parsed certificates

268

* @throws CertificateException if certificate parsing fails

269

* @throws IOException if file reading fails

270

*/

271

public static List<Certificate> readCertificates(Collection<Path> certPaths)

272

throws CertificateException, IOException;

273

}

274

```

275

276

**Usage Examples:**

277

278

```java

279

import org.elasticsearch.common.ssl.PemUtils;

280

import java.security.PrivateKey;

281

import java.security.cert.Certificate;

282

import java.nio.file.Paths;

283

import java.util.List;

284

import java.util.function.Supplier;

285

286

// Read unencrypted private key

287

PrivateKey privateKey = PemUtils.readPrivateKey(

288

Paths.get("/etc/ssl/private/server.key"),

289

() -> null // no password needed

290

);

291

292

// Read encrypted private key

293

PrivateKey encryptedKey = PemUtils.readPrivateKey(

294

Paths.get("/etc/ssl/private/encrypted.key"),

295

() -> "secret123".toCharArray() // provide password when needed

296

);

297

298

// Read encrypted key with interactive password prompt

299

PrivateKey interactiveKey = PemUtils.readPrivateKey(

300

Paths.get("/etc/ssl/private/secure.key"),

301

() -> {

302

System.out.print("Enter key password: ");

303

return System.console().readPassword();

304

}

305

);

306

307

// Parse PEM string directly

308

String pemKeyString = """

309

-----BEGIN PRIVATE KEY-----

310

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...

311

-----END PRIVATE KEY-----

312

""";

313

PrivateKey parsedKey = PemUtils.parsePKCS8PemString(pemKeyString);

314

315

// Read multiple certificate files

316

List<Certificate> certificates = PemUtils.readCertificates(List.of(

317

Paths.get("/etc/ssl/certs/ca.pem"),

318

Paths.get("/etc/ssl/certs/intermediate.pem"),

319

Paths.get("/etc/ssl/certs/server.pem")

320

));

321

322

// Read certificate chain from single file

323

List<Certificate> certChain = PemUtils.readCertificates(List.of(

324

Paths.get("/etc/ssl/certs/fullchain.pem") // file with multiple certificates

325

));

326

```

327

328

### SSL Utilities

329

330

General SSL-related utility methods for certificate operations.

331

332

```java { .api }

333

/**

334

* SSL-related utility methods

335

*/

336

public final class SslUtil {

337

/**

338

* Calculates certificate fingerprint using specified algorithm

339

* @param certificate X509 certificate to fingerprint

340

* @param algorithm hash algorithm (e.g., "SHA-256", "SHA-1", "MD5")

341

* @return hex-encoded fingerprint string

342

* @throws CertificateEncodingException if certificate encoding fails

343

*/

344

public static String calculateFingerprint(X509Certificate certificate, String algorithm)

345

throws CertificateEncodingException;

346

}

347

```

348

349

**Usage Examples:**

350

351

```java

352

import org.elasticsearch.common.ssl.SslUtil;

353

import java.security.cert.X509Certificate;

354

355

// Calculate SHA-256 fingerprint

356

String sha256Fingerprint = SslUtil.calculateFingerprint(certificate, "SHA-256");

357

System.out.println("SHA-256: " + sha256Fingerprint);

358

359

// Calculate SHA-1 fingerprint

360

String sha1Fingerprint = SslUtil.calculateFingerprint(certificate, "SHA-1");

361

System.out.println("SHA-1: " + sha1Fingerprint);

362

363

// Calculate MD5 fingerprint (less secure, for compatibility)

364

String md5Fingerprint = SslUtil.calculateFingerprint(certificate, "MD5");

365

System.out.println("MD5: " + md5Fingerprint);

366

```

367

368

### DER Parser

369

370

Minimal ASN.1 DER decoder for PKCS#1 private keys, providing low-level parsing capabilities.

371

372

```java { .api }

373

/**

374

* Minimal ASN.1 DER decoder for PKCS#1 private keys

375

*/

376

public final class DerParser {

377

/**

378

* Creates DER parser for byte array

379

* @param bytes DER encoded bytes to parse

380

*/

381

public DerParser(byte[] bytes);

382

383

/**

384

* Reads ASN.1 object with required type check

385

* @param requiredType expected ASN.1 type constant

386

* @return parsed ASN.1 object

387

* @throws IOException if parsing fails or type doesn't match

388

*/

389

public Asn1Object readAsn1Object(int requiredType) throws IOException;

390

391

/**

392

* Reads next ASN.1 object without type checking

393

* @return parsed ASN.1 object

394

* @throws IOException if parsing fails

395

*/

396

public Asn1Object readAsn1Object() throws IOException;

397

}

398

```

399

400

### ASN.1 Object Wrapper

401

402

Wrapper for parsed ASN.1 objects with convenient access methods.

403

404

```java { .api }

405

/**

406

* Wrapper for parsed ASN.1 objects

407

*/

408

public static class Asn1Object {

409

/**

410

* Gets the ASN.1 type tag

411

* @return type tag value

412

*/

413

public int getType();

414

415

/**

416

* Gets the content length

417

* @return content length in bytes

418

*/

419

public int getLength();

420

421

/**

422

* Gets the raw content bytes

423

* @return content byte array

424

*/

425

public byte[] getValue();

426

427

/**

428

* Checks if this is a constructed (composite) object

429

* @return true if constructed

430

*/

431

public boolean isConstructed();

432

433

/**

434

* Gets parser for nested content (if constructed)

435

* @return DerParser for nested content

436

* @throws IOException if not constructed or parsing fails

437

*/

438

public DerParser getParser() throws IOException;

439

440

/**

441

* Interprets content as integer value

442

* @return BigInteger value

443

* @throws IOException if content is not a valid integer

444

*/

445

public BigInteger getInteger() throws IOException;

446

447

/**

448

* Interprets content as string value

449

* @return string value

450

* @throws IOException if content is not a valid string

451

*/

452

public String getString() throws IOException;

453

454

/**

455

* Interprets content as object identifier (OID)

456

* @return OID string (e.g., "1.2.840.113549.1.1.1")

457

* @throws IOException if content is not a valid OID

458

*/

459

public String getOid() throws IOException;

460

}

461

```

462

463

### ASN.1 Type Constants

464

465

Constants for ASN.1 type identification.

466

467

```java { .api }

468

/**

469

* ASN.1 type constants

470

*/

471

public static class Type {

472

public static final int INTEGER = 0x02;

473

public static final int OCTET_STRING = 0x04;

474

public static final int OBJECT_OID = 0x06;

475

public static final int SEQUENCE = 0x30;

476

// Additional type constants...

477

}

478

```

479

480

**Usage Examples:**

481

482

```java

483

import org.elasticsearch.common.ssl.DerParser;

484

import org.elasticsearch.common.ssl.DerParser.Asn1Object;

485

import org.elasticsearch.common.ssl.DerParser.Type;

486

import java.math.BigInteger;

487

488

// Parse DER encoded private key

489

byte[] derBytes = // ... DER encoded PKCS#1 private key bytes

490

DerParser parser = new DerParser(derBytes);

491

492

// Read outer SEQUENCE

493

Asn1Object sequence = parser.readAsn1Object(Type.SEQUENCE);

494

DerParser seqParser = sequence.getParser();

495

496

// Read version (INTEGER)

497

Asn1Object version = seqParser.readAsn1Object(Type.INTEGER);

498

BigInteger versionNum = version.getInteger();

499

500

// Read modulus (large INTEGER)

501

Asn1Object modulus = seqParser.readAsn1Object(Type.INTEGER);

502

BigInteger modulusValue = modulus.getInteger();

503

504

// Continue parsing other RSA private key components...

505

```

506

507

## Utility Patterns

508

509

### Keystore Type Detection

510

511

The library automatically detects keystore types:

512

513

```java

514

// File extensions mapped to keystore types:

515

// .jks -> JKS

516

// .p12, .pfx -> PKCS12

517

// .bks -> BKS

518

// others -> JKS (default)

519

520

String type = KeyStoreUtil.inferKeyStoreType("mystore.p12"); // "PKCS12"

521

```

522

523

### Certificate Chain Validation

524

525

When building keystores, ensure proper certificate chain ordering:

526

527

```java

528

// Correct order: end entity certificate first, then intermediates, then root

529

List<Certificate> chainInOrder = List.of(

530

endEntityCert, // certificate for private key

531

intermediateCert, // intermediate CA

532

rootCert // root CA (optional)

533

);

534

535

KeyStore keystore = KeyStoreUtil.buildKeyStore(chainInOrder, privateKey, password);

536

```

537

538

### PEM File Handling

539

540

The PEM utilities handle various PEM formats:

541

542

```java

543

// Supports multiple certificate formats:

544

// - Single certificate per file

545

// - Multiple certificates in one file (certificate chains)

546

// - Mixed certificate and key files (certificates only extracted)

547

548

// Supports multiple private key formats:

549

// - PKCS#8 (-----BEGIN PRIVATE KEY-----)

550

// - PKCS#8 encrypted (-----BEGIN ENCRYPTED PRIVATE KEY-----)

551

// - Legacy RSA format (-----BEGIN RSA PRIVATE KEY-----)

552

```