All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.hana.datalake.files.utils.PemSslUtils Maven / Gradle / Ivy

Go to download

An implementation of org.apache.hadoop.fs.FileSystem targeting SAP HANA Data Lake Files.

There is a newer version: 3.0.27
Show newest version
// © 2022-2023 SAP SE or an SAP affiliate company. All rights reserved.
package com.sap.hana.datalake.files.utils;

import com.sap.hana.datalake.files.HdlfsConstants;
import com.sap.hana.datalake.files.classification.InterfaceAudience;
import com.sap.hana.datalake.files.classification.InterfaceStability;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.openssl.PEMDecryptorProvider;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.openssl.PEMEncryptedKeyPair;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.openssl.PEMKeyPair;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.openssl.PEMParser;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.openssl.bc.BcPEMDecryptorProvider;
import com.sap.hana.datalake.files.shaded.org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

@InterfaceAudience.Private
@InterfaceStability.Evolving
public final class PemSslUtils {

  private static final Pattern PEM_HEADER_PATTERN = Pattern.compile("^-----BEGIN(.+)(CERTIFICATE|PRIVATE KEY)-----(?s).*");
  private static final char[] EMPTY_CHAR_ARRAY = new char[0];
  private static final String KEY_MANAGER_ALGORITHM = "PKIX";

  public static boolean isPemFileContent(final String value) {
    return PEM_HEADER_PATTERN.matcher(value).matches();
  }

  public static KeyManager[] createKeyManagers(final String certificatesValue, final String privateKeyValue) throws IOException, GeneralSecurityException {
    return createKeyManagers(certificatesValue, privateKeyValue, /* passphrase */ null);
  }

  public static KeyManager[] createKeyManagers(final String certificatesValue, final String privateKeyValue, final String passphrase) throws IOException, GeneralSecurityException {
    if (certificatesValue == null || certificatesValue.isEmpty() || privateKeyValue == null || privateKeyValue.isEmpty()) {
      return null;
    }

    final List certificateChain = isPemFileContent(certificatesValue) ?
            loadCertificateChain(certificatesValue) :
            loadCertificateChain(Paths.get(certificatesValue));

    final PrivateKey privateKey = isPemFileContent(privateKeyValue) ?
            loadPrivateKey(privateKeyValue, passphrase) :
            loadPrivateKey(Paths.get(privateKeyValue), passphrase);

    return createKeyManagers(certificateChain, privateKey);
  }

  public static KeyManager[] createKeyManagers(final List certChain, final PrivateKey privateKey) throws GeneralSecurityException, IOException {
    if (certChain == null || privateKey == null) {
      return null;
    }

    final KeyStore keyStore = createEmptyJavaKeyStore();
    final Certificate[] certChainArray = certChain.toArray(new Certificate[0]);

    keyStore.setKeyEntry("client-identity", privateKey, EMPTY_CHAR_ARRAY, certChainArray);

    final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KEY_MANAGER_ALGORITHM);
    keyManagerFactory.init(keyStore, EMPTY_CHAR_ARRAY);

    return keyManagerFactory.getKeyManagers();
  }

  public static TrustManager[] createTrustManagers(final String caCertsValue) throws IOException, GeneralSecurityException {
    if (caCertsValue == null || caCertsValue.isEmpty()) {
      return null;
    }

    final List caCerts = isPemFileContent(caCertsValue) ?
            loadCertificateChain(caCertsValue) :
            loadCertificateChain(Paths.get(caCertsValue));

    return createTrustManagers(caCerts);
  }

  public static TrustManager[] createTrustManagers(final List caCerts) throws IOException, GeneralSecurityException {
    if (caCerts == null) {
      return null;
    }

    final KeyStore trustStore = createEmptyJavaKeyStore();

    for (int i = 0; i < caCerts.size(); i++) {
      trustStore.setCertificateEntry("ca" + i, caCerts.get(i));
    }

    final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(KEY_MANAGER_ALGORITHM);
    trustManagerFactory.init(trustStore);

    return trustManagerFactory.getTrustManagers();
  }

  private static KeyStore createEmptyJavaKeyStore() throws IOException, GeneralSecurityException {
    final KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(null, null);

    return keyStore;
  }

  private static List loadCertificateChain(final Path certsPath) throws IOException, GeneralSecurityException {
    try (final InputStream is = Files.newInputStream(certsPath)) {
      return loadCertificateChain(is);
    }
  }

  private static List loadCertificateChain(final String certsData) throws IOException, GeneralSecurityException {
    try (final InputStream is = new ByteArrayInputStream(certsData.getBytes(HdlfsConstants.DEFAULT_CHARSET))) {
      return loadCertificateChain(is);
    }
  }

  private static List loadCertificateChain(final InputStream certsDataInputStream) throws IOException, GeneralSecurityException {
    final CertificateFactory factory = new CertificateFactory();
    final List certificates = new ArrayList<>();

    try (final BufferedInputStream bis = new BufferedInputStream(certsDataInputStream)) {
      while (bis.available() > 0) {
        final Certificate cert = factory.engineGenerateCertificate(bis);
        certificates.add(cert);
      }

      return certificates;
    }
  }

  private static PrivateKey loadPrivateKey(final Path privateKeyPath, final String passphrase) throws IOException {
    try (final InputStream privateKeyIn = Files.newInputStream(privateKeyPath);
         final Reader privateKeyReader = new InputStreamReader(privateKeyIn)) {
      return loadPrivateKey(privateKeyReader, passphrase);
    }
  }

  private static PrivateKey loadPrivateKey(final String privateKeyData, final String passphrase) throws IOException {
    try (final Reader privateKeyReader = new StringReader(privateKeyData)) {
      return loadPrivateKey(privateKeyReader, passphrase);
    }
  }

  private static PrivateKey loadPrivateKey(final Reader privateKeyReader, final String passphrase) throws IOException {
    final PEMParser pemParser = new PEMParser(privateKeyReader);
    final Object parsedObject = pemParser.readObject();
    final PrivateKeyInfo privateKeyInfo;

    if (parsedObject instanceof PrivateKeyInfo) {
      privateKeyInfo = (PrivateKeyInfo) parsedObject;
    } else if (parsedObject instanceof PEMKeyPair) {
      privateKeyInfo = ((PEMKeyPair) parsedObject).getPrivateKeyInfo();
    } else if (parsedObject instanceof PEMEncryptedKeyPair) {
      final char[] passphraseChars = Optional.ofNullable(passphrase).orElse(HdlfsConstants.FS_HDLFS_SSL_KEYFILE_PASSWORD_DEFAULT).toCharArray();
      final PEMDecryptorProvider decryptorProvider = new BcPEMDecryptorProvider(passphraseChars);
      final PEMKeyPair pemKeyPair = ((PEMEncryptedKeyPair) parsedObject).decryptKeyPair(decryptorProvider);

      privateKeyInfo = pemKeyPair.getPrivateKeyInfo();
    } else {
      throw new IOException(String.format("Unsupported PrivateKey; parsed object class [%s]", parsedObject.getClass().getName()));
    }

    return privateKeyInfo == null ? null : new JcaPEMKeyConverter().getPrivateKey(privateKeyInfo);
  }

}

// © 2022-2023 SAP SE or an SAP affiliate company. All rights reserved.




© 2015 - 2025 Weber Informatics LLC | Privacy Policy