Skip to content

Commit

Permalink
Added option for extracting PublicKey
Browse files Browse the repository at this point in the history
  • Loading branch information
Hakky54 committed Nov 5, 2023
1 parent fe4ca7c commit 653ce83
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
*/
public final class PublicKeyParseException extends PemParseException {

public PublicKeyParseException(Throwable cause) {
super(cause);
}

public PublicKeyParseException(String message) {
super(message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import nl.altindag.ssl.pem.exception.CertificateParseException;
import nl.altindag.ssl.pem.exception.PemParseException;
import nl.altindag.ssl.pem.exception.PrivateKeyParseException;
import nl.altindag.ssl.pem.exception.PublicKeyParseException;
import nl.altindag.ssl.util.KeyManagerUtils;
import nl.altindag.ssl.util.TrustManagerUtils;
import nl.altindag.ssl.util.internal.IOUtils;
Expand All @@ -35,19 +36,25 @@
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.X509TrustedCertificateBlock;
import org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.file.Path;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
Expand Down Expand Up @@ -519,6 +526,31 @@ private static PrivateKey extractPrivateKey(PrivateKeyInfo privateKeyInfo) {
}
}

public static PublicKey extractPublicKey(PrivateKey privateKey) {
try(StringWriter writer = new StringWriter()) {
JcaMiscPEMGenerator pemGenerator = new JcaMiscPEMGenerator(privateKey, null);
PemObject pemObject = pemGenerator.generate();

PemWriter pemWriter = new PemWriter(writer);
pemWriter.writeObject(pemObject);
pemWriter.close();

try(StringReader stringReader = new StringReader(writer.toString());
PEMParser pemParser = new PEMParser(stringReader)) {
Object object = pemParser.readObject();
if (object instanceof PEMKeyPair) {
PEMKeyPair pemKeyPair = (PEMKeyPair) object;
KeyPair keyPair = getInstance().getKeyConverter().getKeyPair(pemKeyPair);
return keyPair.getPublic();
} else {
throw new PublicKeyParseException("Could not extract public key for the given private key.");
}
}
} catch (IOException exception) {
throw new PublicKeyParseException(exception);
}
}

static PemUtils getInstance() {
return INSTANCE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import nl.altindag.ssl.pem.exception.CertificateParseException;
import nl.altindag.ssl.pem.exception.PemParseException;
import nl.altindag.ssl.pem.exception.PrivateKeyParseException;
import nl.altindag.ssl.pem.exception.PublicKeyParseException;
import nl.altindag.ssl.util.KeyStoreUtils;
import nl.altindag.ssl.util.internal.IOUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
Expand Down Expand Up @@ -49,6 +50,7 @@
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Optional;
Expand Down Expand Up @@ -389,7 +391,6 @@ void throwGenericIOExceptionWhenInputStreamCanNotBeClosed() throws IOException {
.hasRootCauseMessage("KABOOM!!!");
}


@Test
void loadUnencryptedPrivateKeyFromClassPath() {
PrivateKey privateKey = PemUtils.loadPrivateKey(PEM_LOCATION + "unencrypted-identity.pem");
Expand Down Expand Up @@ -495,6 +496,15 @@ void parseUnencryptedPrivateKeyFromContent() {
assertThat(privateKey).isNotNull();
}

@Test
void extractPublicKeyFromPrivateKey() {
String identityContent = getResourceContent(PEM_LOCATION + "encrypted-identity.pem");
PrivateKey privateKey = PemUtils.parsePrivateKey(identityContent, DEFAULT_PASSWORD);
PublicKey publicKey = PemUtils.extractPublicKey(privateKey);

assertThat(publicKey).isNotNull();
}

@Test
void parseSingleTrustMaterialFromContentAsAsOneLiner() {
String certificateContent = getResourceContent(PEM_LOCATION + "one-liner-stackexchange.pem");
Expand Down Expand Up @@ -575,7 +585,7 @@ void throwsIllegalArgumentExceptionWhenUnsupportedEncryptedRsaPrivateKeyIsProvid
@Test
void loadUnEncryptedRsaIdentityMaterialFromContentAsOneLiner() {
String identityContent = getResourceContent(PEM_LOCATION + "one-liner-unencrypted-rsa-identity.pem");
X509ExtendedKeyManager keyManager = PemUtils.parseIdentityMaterial(identityContent, null);
X509ExtendedKeyManager keyManager = PemUtils.parseIdentityMaterial(identityContent);

assertThat(keyManager).isNotNull();
}
Expand Down Expand Up @@ -851,6 +861,12 @@ void throwGenericKeyStoreWhenSetKeyEntryThrowsKeyStoreException() throws KeyStor
}
}

@Test
void throwsPublicKeyParseExceptionForUnknownPrivateKeyWhenAttemptingToExtractPublicKey() {
assertThatThrownBy(() -> PemUtils.extractPublicKey(null))
.isInstanceOf(PublicKeyParseException.class);
}

private String getResourceContent(String path) {
try(InputStream resource = getResource(path);
InputStreamReader inputStreamReader = new InputStreamReader(resource, StandardCharsets.UTF_8);
Expand Down

0 comments on commit 653ce83

Please sign in to comment.