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

org.neo4j.driver.internal.pki.PemParser Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [https://neo4j.com]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.neo4j.driver.internal.pki;

import static java.lang.String.format;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * Parse a public or private key.
 * 

* In contrast to {@link CertificateFactory}, Java's {@link KeyFactory}'s does not support reading textual pem files. * PEM format reference: RFC7468 * This implementation has support for *

  • PKCS#8/X.509 Public Key *
  • PKCS#8 and encrypted PKCS#8 private keys *
  • PKCS#1 encoded RSA, DSA and EC. *
  • Encrypted PKCS#1 encoded RSA, DSA and EC. */ public final class PemParser { private static final String BEGIN = "-----BEGIN "; private static final String END = "-----END "; /** * Mime decoder is almost identical to PEM specification. *

    * RFC2045 */ private static final Base64.Decoder BASE_64 = Base64.getMimeDecoder(); private static final Map parsers; static { parsers = Map.of( PemFormats.Pkcs8.PUBLIC_LABEL, new PemFormats.Pkcs8(), PemFormats.Pkcs8.PRIVATE_LABEL, new PemFormats.Pkcs8(), PemFormats.Pkcs8Encrypted.ENCRYPTED_LABEL, new PemFormats.Pkcs8Encrypted(), PemFormats.PemPKCS1Rsa.PUBLIC_LABEL, new PemFormats.PemPKCS1Rsa(), PemFormats.PemPKCS1Rsa.PRIVATE_LABEL, new PemFormats.PemPKCS1Rsa(), PemFormats.PemPKCS1Dsa.PRIVATE_LABEL, new PemFormats.PemPKCS1Dsa(), PemFormats.PemPKCS1Ec.PRIVATE_LABEL, new PemFormats.PemPKCS1Ec()); } private String label; private byte[] der; private final Map headers = new HashMap<>(); public PemParser(InputStream in) throws IOException { try (var reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.US_ASCII))) { parse(reader); } } public PrivateKey getPrivateKey(String password) throws KeyException { var pemFormat = parsers.get(label); if (pemFormat != null) { return pemFormat.decodePrivate(der, headers, password); } throw new KeyException(format("Provided PEM does not contain a private key, found '%s'.", label)); } public PublicKey getPublicKey() throws KeyException { var pemFormat = parsers.get(label); if (pemFormat != null) { return pemFormat.decodePublicKey(der); } throw new KeyException(format("Provided PEM does not contain a public key, found '%s'.", label)); } /** * Read the input stream and extract all the components. * @throws IOException on failure to read from the provided input stream. */ private void parse(BufferedReader reader) throws IOException { // Find header, explanatory text is allowed before and after block, so ignore that var line = reader.readLine(); while (line != null && !line.startsWith(BEGIN)) { line = reader.readLine(); } if (line == null) { throw new IllegalStateException("File does not contain " + BEGIN + " encapsulation boundary."); } // Get label label = extractLabel(line); var endMarker = END + label; // Extract base64 encoded DER var sb = new StringBuilder(); while ((line = reader.readLine()) != null) { if (line.contains(endMarker)) { der = BASE_64.decode(sb.toString()); return; } // Look for headers, is allowed in legacy PEM if (line.contains(":")) { var kv = line.split(":"); headers.put(kv[0].trim(), kv[1].trim()); continue; } sb.append(line.trim()); } throw new IllegalStateException("Missing footer: " + endMarker + "."); } /** * Extract the label from the format {@code -----BEGIN (label)-----}. * @param line line containing the pre-encapsulation boundary. * @return the label for the encapsulation. */ private static String extractLabel(String line) { line = line.substring(BEGIN.length()); var index = line.indexOf('-'); if (!line.endsWith("-----") || (line.length() - index) != "-----".length()) { throw new IllegalStateException( format("Unable to find label, expecting '-----BEGIN (label)-----' but found '%s'.", line)); } return line.substring(0, index); } }





  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy