static Optional<PrivateKey> resolvePrivateKey(Config config) { KeyConfig.PemBuilder pemBuilder = KeyConfig.pemBuilder().config(config); KeyConfig.KeystoreBuilder keystoreBuilder = KeyConfig.keystoreBuilder().config(config); .ifPresent(keystoreBuilder::keyAlias); Optional<PrivateKey> result = KeyConfig.fullBuilder() .updateWith(pemBuilder) .updateWith(keystoreBuilder) .build() .privateKey();
/** * For algorithms based on public/private key (such as rsa-sha256), this provides access to the public key of the client. * * @param keyConfig keys configured to access a public key to validate signature * @return updated builder instance */ public Builder publicKeyConfig(KeyConfig keyConfig) { if (null == algorithm) { algorithm = HttpSignProvider.ALGORITHM_RSA; } // make sure this is a public key (validation of inbound signatures) keyConfig.publicKey() .orElseThrow(() -> new HttpSignatureException("Configuration must contain a public key")); this.keyConfig = keyConfig; return this; }
/** * Build a new instance of the configuration based on this builder. * * @return instance from this builder * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured */ @Override public KeyConfig build() throws PkiException { PrivateKey privateKey = this.explicitPrivateKey; PublicKey publicKey = this.explicitPublicKey; X509Certificate publicCert = this.explicitPublicCert; List<X509Certificate> certChain = new LinkedList<>(explicitCertChain); List<X509Certificate> certificates = new LinkedList<>(explicitCertificates); // fix public key if cert is provided if (null == publicKey && null != publicCert) { publicKey = publicCert.getPublicKey(); } return new KeyConfig(privateKey, publicKey, publicCert, certChain, certificates); }
private static KeyManagerFactory buildKmf(KeyConfig privateKeyConfig) throws IOException, GeneralSecurityException { String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); if (algorithm == null) { algorithm = "SunX509"; } byte[] passwordBytes = new byte[64]; RANDOM.nextBytes(passwordBytes); char[] password = Base64.getEncoder().encodeToString(passwordBytes).toCharArray(); KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, null); ks.setKeyEntry("key", privateKeyConfig.privateKey().orElseThrow(() -> new RuntimeException("Private key not available")), password, privateKeyConfig.certChain().toArray(new Certificate[0])); KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); kmf.init(ks, password); return kmf; }
/** * Updated this builder instance from configuration. * Keys configured will override existing fields in this builder, others will be left intact. * If certification path is already defined, configuration based cert-path will be added. * * @param config configuration to update this builder from * @return updated builder instance */ public Builder config(Config config) { updateWith(pemBuilder().config(config)); updateWith(keystoreBuilder().config(config)); return this; } }
private JwkKeys loadPlainPublicKey(String stringContent) { return JwkKeys.builder() .addKey(JwkRSA.builder() .publicKey((RSAPublicKey) KeyConfig.pemBuilder() .publicKey(Resource.create("public key from PKCS8", stringContent)) .build() .publicKey() .orElseThrow(() -> new DeploymentException( "Failed to load public key from string content"))) .build()) .build(); }
KeyConfig kc = KeyConfig.keystoreBuilder() .keystore(Resource.create(keyPath)) .keystorePassphrase(cliArgs[2].toCharArray()) .build(); publicKey = kc.publicKey() .orElseThrow(() -> new ValidationException("There is no public key available for cert alias: " + certAlias));
/** * Private key configuration for RSA based algorithms. * If called sets the algorithm to "rsa-sha256". Expects either explicit private key, or keystore and private key * alias. * * @param keyConfig private key configuration for outbound signatures * @return updated builder instance */ public Builder privateKeyConfig(KeyConfig keyConfig) { if (null == algorithm) { algorithm = HttpSignProvider.ALGORITHM_RSA; } // make sure this is a private key (signature of outbound requests) keyConfig.privateKey() .orElseThrow(() -> new HttpSignatureException("Configuration must contain a private key")); this.keyConfig = keyConfig; return this; }
/** * Create a builder for {@link KeyConfig} from this keystore builder. This allows you to enhance the config * with additional (explicit) fields. * * @return builder of {@link KeyConfig} */ public Builder toFullBuilder() { return updateBuilder(KeyConfig.fullBuilder()); }
private static TrustManagerFactory buildTmf(KeyConfig trustConfig) throws IOException, GeneralSecurityException { List<X509Certificate> certs; if (trustConfig == null) { certs = CollectionsHelper.listOf(); } else { certs = trustConfig.certs(); } KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, null); int i = 1; for (X509Certificate cert : certs) { ks.setCertificateEntry(String.valueOf(i), cert); i++; } TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); return tmf; }
/** * Creates {@link SSLContext} from the provided configuration. * * @param sslConfig the ssl configuration * @return a built {@link SSLContext} * @throws IllegalStateException in case of a problem; will wrap either an instance of {@link IOException} or * a {@link GeneralSecurityException} */ public static SSLContext create(Config sslConfig) { return new SSLContextBuilder().privateKeyConfig(KeyConfig.create(sslConfig.get("private-key"))) .sessionCacheSize(sslConfig.get("session-cache-size").asInt().orElse(0)) .sessionTimeout(sslConfig.get("session-timeout").asInt().orElse(0)) .trustConfig(KeyConfig.create(sslConfig.get("trust"))) .build(); }
private JwkKeys loadPlainPublicKey(String stringContent) { return JwkKeys.builder() .addKey(JwkRSA.builder() .publicKey((RSAPublicKey) KeyConfig.pemBuilder() .publicKey(Resource.create("public key from PKCS8", stringContent)) .build() .publicKey() .orElseThrow(() -> new DeploymentException( "Failed to load public key from string content"))) .build()) .build(); }
/** * Updated this builder instance from configuration. * Keys configured will override existing fields in this builder, others will be left intact. * If certification path is already defined, configuration based cert-path will be added. * * @param config configuration to update this builder from * @return updated builder instance */ public Builder config(Config config) { updateWith(pemBuilder().config(config)); updateWith(keystoreBuilder().config(config)); return this; } }
KeyConfig kc = KeyConfig.keystoreBuilder() .keystore(Resource.create(keyPath)) .keystorePassphrase(cliArgs[2].toCharArray()) .build(); publicKey = kc.publicKey() .orElseThrow(() -> new ValidationException("There is no public key available for cert alias: " + certAlias));
private byte[] signRsaSha256(SecurityEnvironment env, KeyConfig keyConfig, Map<String, List<String>> newHeaders) { try { Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(keyConfig.privateKey().orElseThrow(() -> new HttpSignatureException( "Private key is required, yet not " + "configured"))); signature.update(getBytesToSign(env, newHeaders)); return signature.sign(); } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) { throw new HttpSignatureException(e); } }
/** * Get a builder filled from this builder to add additional information (such as public key from certificate etc.). * * @return builder for {@link KeyConfig} */ public Builder toFullBuilder() { return updateBuilder(KeyConfig.fullBuilder()); }
static Optional<PrivateKey> resolvePrivateKey(Config config) { KeyConfig.PemBuilder pemBuilder = KeyConfig.pemBuilder().config(config); KeyConfig.KeystoreBuilder keystoreBuilder = KeyConfig.keystoreBuilder().config(config); .ifPresent(keystoreBuilder::keyAlias); Optional<PrivateKey> result = KeyConfig.fullBuilder() .updateWith(pemBuilder) .updateWith(keystoreBuilder) .build() .privateKey();
private EncryptionFilter(Builder builder, Config config) { if (builder.fromConfig) { this.requireEncryption = OptionalHelper.from(EncryptionUtil.getEnv(ConfigProperties.REQUIRE_ENCRYPTION_ENV_VARIABLE) .map(Boolean::parseBoolean)) .or(() -> config.get(ConfigProperties.REQUIRE_ENCRYPTION_CONFIG_KEY).asBoolean().asOptional()) .asOptional() .orElse(true); this.masterPassword = EncryptionUtil.resolveMasterPassword(requireEncryption, config).orElse(null); this.privateKey = EncryptionUtil.resolvePrivateKey(config.get("security.config.rsa")) .orElse(null); } else { this.requireEncryption = builder.requireEncryption; this.privateKey = builder.privateKeyConfig.privateKey() .orElseThrow(() -> new ConfigEncryptionException("Private key configuration is invalid")); this.masterPassword = builder.masterPassword; } if (null != privateKey && !(privateKey instanceof RSAPrivateKey)) { throw new ConfigEncryptionException("Private key must be an RSA private key, but is: " + privateKey.getClass().getName()); } ConfigFilter noOp = (key, stringValue) -> stringValue; aesFilter = (null == masterPassword ? noOp : (key, stringValue) -> decryptAes(masterPassword, stringValue)); rsaFilter = (null == privateKey ? noOp : (key, stringValue) -> decryptRsa(privateKey, stringValue)); clearFilter = this::clearText; aliasFilter = (key, stringValue) -> aliased(stringValue, config); }
/** * Load key config from config. * * @param config config instance located at keys configuration (expects "keystore-path" child) * @return KeyConfig loaded from config * @throws PkiException when keys or certificates fail to load from keystore or when misconfigured */ public static KeyConfig create(Config config) throws PkiException { try { return fullBuilder().config(config).build(); } catch (ResourceException e) { throw new PkiException("Failed to load from config", e); } }
private Optional<String> validateRsaSha256(SecurityEnvironment env, InboundClientDefinition clientDefinition) { try { Signature signature = Signature.getInstance("SHA256withRSA"); signature.initVerify(clientDefinition.keyConfig() .orElseThrow(() -> new HttpSignatureException("RSA public key configuration is " + "required")) .publicKey() .orElseThrow(() -> new HttpSignatureException( "Public key is required, yet not configured"))); signature.update(getBytesToSign(env, null)); if (!signature.verify(this.signatureBytes)) { return Optional.of("Signature is not valid"); } return Optional.empty(); } catch (NoSuchAlgorithmException e) { LOGGER.log(Level.FINEST, "SHA256withRSA algorithm not found", e); return Optional.of("SHA256withRSA algorithm not found: " + e.getMessage()); } catch (InvalidKeyException e) { LOGGER.log(Level.FINEST, "Invalid RSA key", e); return Optional.of("Invalid RSA key: " + e.getMessage()); } catch (SignatureException e) { LOGGER.log(Level.FINEST, "Signature exception", e); return Optional.of("SignatureException: " + e.getMessage()); } }