We are working on encryption-decryption using applet. We find some unexpected issue with digital certificate. One system has certificate and we can't find the private key from that certificate but by installing the same certificate again works fine.
Java Plug-in 10.25.2.17
Using JRE version 1.7.0_25-b17 Java HotSpot(TM) 64-Bit Server VM
User home directory = C:\Users\admin
To access private key we are using below code.
private PrivateKey getPrivateKeyFromKeyStore(String pubkey, KeyStore browser) {
PrivateKey privateKey = null;
String pubKey1 = "";
if (browser != null) {
try {
Field spiField = KeyStore.class.getDeclaredField("keyStoreSpi");
spiField.setAccessible(true);
KeyStoreSpi spi = (KeyStoreSpi) spiField.get(browser);
Field entriesField = spi.getClass().getSuperclass().getDeclaredField("entries");
entriesField.setAccessible(true);
#SuppressWarnings("rawtypes")
Collection entries = (Collection) entriesField.get(spi);
for (Object entry : entries) {
String alias = (String) invokeGetter(entry, "getAlias");
X509Certificate[] certificateChain = (X509Certificate[]) invokeGetter(entry, "getCertificateChain");
for (X509Certificate current : certificateChain) {
pubKey1 = this.bASE64Encoder.encode(current.getPublicKey().getEncoded());
if (pubkey.equals(pubKey1) && !pubkey.equals("")) {
privateKey = (PrivateKey) invokeGetter(entry, "getPrivateKey");
return privateKey;
}
}
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return privateKey;
}
You won't find private key in certificate because it must be in your keystore, of course, if you generated your cert with its CSR :)
As a tip, I may ask is the cert expired for example?
Anyway, the question is pretty unclear :( If you have cert you must have the keystore which was used to sign your app... It would be better you give more details...
Related
I'm trying to check whether a certificate is self-signed.
public static void main(String[] args) throws CertificateException, IOException, GeneralSecurityException
{
// InputStream is = new URL("http://www.d-trust.net/cgi-bin/D-TRUST_Root_CA_2_2021.crt").openStream(); // ok
InputStream is = new URL("http://www.d-trust.net/cgi-bin/D-TRUST_Root_CA_1_2017.crt").openStream(); // not ok
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(is);
System.out.println(cert);
System.out.println("Self signed? " + isSelfSigned(cert));
}
public static boolean isSelfSigned(X509Certificate cert) throws GeneralSecurityException
{
try
{
// Try to verify certificate signature with its own public key
PublicKey key = cert.getPublicKey();
System.out.println("key class: " + key.getClass().getName());
System.out.println("Algorithm: " + key.getAlgorithm());
cert.verify(key, new BouncyCastleProvider());
return true;
}
catch (SignatureException | InvalidKeyException ex)
{
// Invalid signature --> not self-signed
ex.printStackTrace();
return false;
}
}
I get this exception in isSelfSigned():
java.security.InvalidKeyException: Supplied key is not a RSAPublicKey instance
at org.bouncycastle.jcajce.provider.asymmetric.rsa.PSSSignatureSpi.engineInitVerify(Unknown Source)
at java.security.Signature$Delegate.engineInitVerify(Signature.java:1168)
at java.security.Signature.initVerify(Signature.java:460)
at sun.security.x509.X509CertImpl.verify(X509CertImpl.java:483)
at NewClass1.isSelfSigned(NewClass1.java:46)
at NewClass1.main(NewClass1.java:35)
This happens only with one of the URLs in my code, not the other one. The problematic certificate has algorithm 1.2.840.113549.1.1.10, which is RSASSA-PSS. I'm using BouncyCastle bcmail-jdk18on 1.72, which also uses bcprov-jdk18on and bcpkix-jdk18on as dependencies.
I'm assuming that this is a self-signed certificate, but of course I don't know for sure.
It turned out to be a java bug. I was using an older jdk8 version, and it runs fine on the current jdk8 version (Amazon Corretto 1.8.0_352). Thanks Topaco for your help.
I generated ed25519 keypair with my code, but when i copy the public key file and private key file to the linux machine.It looks like there is something wrong with my key pair file.
linux machine can't login with keypair file
this is my code:
public static void main(String[] args) throws Exception {
createED25519();
}
private static void createED25519() throws IOException {
KeyPairGeneratorSpi.Ed25519 ed25519 = new KeyPairGeneratorSpi.Ed25519();
ed25519.initialize(256, new SecureRandom());
KeyPair keyPair = ed25519.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
writeEd25519PrivateKey(privateKey);
writeEd25519PublicKey(publicKey);
}
private static void writeEd25519PrivateKey(PrivateKey privateKey) throws IOException {
try (PemWriter w = new PemWriter(new FileWriter("D:\\keypair\\Ed25519\\java.pem"))) {
Ed25519PrivateKeyParameters ed25519PrivateKeyParameters = (Ed25519PrivateKeyParameters) PrivateKeyFactory
.createKey(privateKey.getEncoded());
byte[] content = OpenSSHPrivateKeyUtil.encodePrivateKey(ed25519PrivateKeyParameters);
PemObject o = new PemObject("OPENSSH PRIVATE KEY", content);
w.writeObject(o);
}
}
private static void writeEd25519PublicKey(PublicKey publicKey) throws IOException {
try (FileWriter fileWriter = new FileWriter("D:\\keypair\\Ed25519\\java.pub")) {
Ed25519PublicKeyParameters publicKeyParameters = (Ed25519PublicKeyParameters) PublicKeyFactory
.createKey(publicKey.getEncoded());
String publicKeyPub = "ssh-ed25516 " + Base64.getEncoder().encodeToString(OpenSSHPublicKeyUtil.encodePublicKey(publicKeyParameters));
fileWriter.write(publicKeyPub);
}
}
pom.xml:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.67</version>
</dependency>
The content of the generated public key is:
ssh-ed25516 AAAAC3NzaC1lZDI1NTE5AAAAIJC+iPZZ56a7wogB/UxlmSbrN2hjaOnu26b2pVX6zkZr
The content of the generated private key is:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz
c2gtZWQyNTUxOQAAACCQvoj2Weemu8KIAf1MZZkm6zdoY2jp7tum9qVV+s5GawAA
AIhAEzACQBMwAgAAAAtzc2gtZWQyNTUxOQAAACCQvoj2Weemu8KIAf1MZZkm6zdo
Y2jp7tum9qVV+s5GawAAAED5xx3tLFBLSXC/SE1dSKL3vuUs9mj2+3/086sbXePu
TJC+iPZZ56a7wogB/UxlmSbrN2hjaOnu26b2pVX6zkZrAAAAAAECAwQF
-----END OPENSSH PRIVATE KEY-----
Hope someone can tell what's wrong with the code, or is there any other way to generate the ED25519 key pair file for SSH login, thanks!
I think the fact that there has been no response, is there is likely nothing wrong with your code, getting a password prompt is more indicative of sshd_config.d/overrides.conf issues. Ensure PubkeyAuthentication yes is present. Then when trying to ssh, using (multiple) -v flags to find the issues, e.g ssh -vvv user#host. This is not a java issue, unless you can't verify the public key against the private key, in code.
Edit: When looking at the verbose output, check to see if there is anything wrong with id_ed25516 rather than id_ed22519 of your public key file. That part is hardcoded via string here String publicKeyPub = "ssh-ed25516 "
With Bouncy Castle added as a provider, the following piece of code:
private static boolean isSelfSigned(final X509Certificate cert) {
try {
final PublicKey key = cert.getPublicKey();
cert.verify(key);
return true;
} catch (final RuntimeException re) {
LOG.warn(re, "isSelfSigned: error.");
return false;
} catch (final GeneralSecurityException gse) {
LOG.warn(gse, "isSelfSigned: error.");
return false;
}
}
Results in the following two errors depending on the implementation class of cert:
java.security.InvalidKeyException: Supplied key (org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey) is not a RSAPublicKey instance
or
java.security.InvalidKeyException: Supplied key (sun.security.ec.ECPublicKeyImpl) is not a RSAPublicKey instance
Does Bouncy Castle not support verifying EC signed certificates? There doesn't appear to be any parameters where I can indicate the keys are not RSA. How do I verify an EC signed certificate using Bouncy Castle?
This was a misunderstanding on my part. The check fails because the certificate does in fact have an EC key, but the parent certificate has an RSA key.
I have an application that needs to run plug-ins written by the same company, but discovered at run-time.
For security, I want the application to authenticate that each plug-in was written by us. No third-party code needs to perform the authentication.
What is an easy way to perform this authentication?
Is it reasonable to get by with challenge-response, or do I need to sign the plug-in jar?
If I need to sign the plug-in jar, what APIs would I use to authenticate?
This is the answer I came to after reading and experimentation.
In this case, a self-signed certificate may be sufficient, since no third-party code needs to authenticate. The hosting code can use the public key to verify the plug-in.
Details
The examples below use the default key algorithm. You may wish to specify a more secure algorithm with -keyalg.
Make the keystore, a public/private key pair, and a self-signed certificate containing the public key
keytool -genkeypair -alias myalias -validity 365 -keystore mykeystore
Validity is measured in days.
Export the certificate containing the public key
keytool -export -keystore mykeystore -alias myalias -file mycertificate.cer
At build time, sign the plug-in jar
jarsigner -keystore mykeystore -signedjar my_signed.jar my_unsigned.jar myalias
At run time, authenticate the plug-in jar contents
This test harness can be used to test the code that follows.
public class CEVerify {
public static void main(String[] args) throws IOException, CertificateException {
File jarFile = new File( "C:\\myplugins\\my_signed.jar" );
String certificatePath = "C:\\mycertificates\\mycertificate.cer";
File certificateFile = new File( certificatePath );
PublicKey publicKey = getPublicKeyFromCertificate( certificateFile );
JarFile jar = new JarFile( jarFile );
boolean isVerified = verify( jar, publicKey );
if ( isVerified ) {
System.out.println( "Verified!" );
}
else {
System.err.println( "NOT verified!" );
}
}
You can extract the public key from the certificate like this:
private static PublicKey
getPublicKeyFromCertificate( File certificateFile )
throws CertificateException, FileNotFoundException
{
CertificateFactory certificateFactory = CertificateFactory.getInstance( "X.509" );
FileInputStream inCertificate = new FileInputStream( certificateFile );
Certificate certificate = certificateFactory.generateCertificate( inCertificate );
return certificate.getPublicKey();
}
Given a jar file and a public key, you can verify appropriate entries in the jar. You may need to exclude other files if you used a different -keyalg, like RSA.
private static boolean
verify( JarFile jar, PublicKey publicKey ) throws IOException {
Enumeration<JarEntry> jarEntries = jar.entries();
while ( jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
if ( jarEntry.isDirectory()) {
continue;
}
else {
String entryName = jarEntry.getName();
if ( entryName.endsWith( ".SF" ) || entryName.endsWith( ".DSA" )) {
continue;
}
else if ( ! verifyJarEntry( jar, publicKey, jarEntry )) {
return false;
}
}
}
return true;
}
And this authenticates a particular file in a jar. Note the need to read all the bytes in the jar entry before its certificates can be obtained.
private static boolean
verifyJarEntry( JarFile jar, PublicKey publicKey, JarEntry jarEntry)
throws IOException
{
try {
InputStream in = jar.getInputStream( jarEntry );
readAllOf( in );
// public Certificate[] getCertificates()
// ... This method can only be called once the JarEntry has been
// completely verified by reading from the entry input stream
// until the end of the stream has been reached. Otherwise, this
// method will return null.
Certificate[] certificates = jarEntry.getCertificates();
if ((null == certificates) || (0 == certificates.length)) {
return false;
} else {
for (int i = 0; i < certificates.length; ++i) {
Certificate certificate = certificates[i];
try {
certificate.verify( publicKey );
return true;
} catch (Exception e) {
continue;
}
}
return false;
}
} catch (SecurityException e) {
return false;
}
}
Finally, this is the method called above to read all the bytes in a jar entry.
private static void readAllOf(InputStream in) throws IOException {
byte[] buffer = new byte[4096];
while ( 0 < in.read( buffer )) {
continue;
}
}
i use custom DummySocketFactory and DummyTrustMAnager to connect to smtp over TLS.
DummySocketFactory:
package XMailMessenger;
public class DummySSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory factory;
public DummySSLSocketFactory() {
try {
SSLContext sslcontext = SSLContext.getInstance("TLS");
//Security.removeProvider("SunJSSE");
sslcontext.init(null,
new TrustManager[] { new DummyTrustManager()},
null );
factory = (SSLSocketFactory)sslcontext.getSocketFactory();
} catch(Exception ex) {
System.out.println(ex.toString());
}
}
public static SocketFactory getDefault() {
SocketFactory a = new DummySSLSocketFactory();
if ( a == null ) { System.out.println("1"); }
return a;
}
...
DummyTrustManager:
public class DummyTrustManager implements X509TrustManager{
public void checkClientTrusted(X509Certificate[] cert, String authType) {
// everything is trusted
}
public void checkServerTrusted(X509Certificate[] cert, String authType) {
// everything is trusted
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
//return null;
}
}
in sending e-mail i receive exception as in subject, this exception goes from function sslcontext.init in DummySSLSocketFactory. I debug it and noticed , that in code:
private X509TrustManager chooseTrustManager(TrustManager[] tm)
throws KeyManagementException {
// We only use the first instance of X509TrustManager passed to us.
for (int i = 0; tm != null && i < tm.length; i++) {
if (tm[i] instanceof X509TrustManager) {
if (SunJSSE.isFIPS() &&
!(tm[i] instanceof X509TrustManagerImpl)) {
throw new KeyManagementException
("FIPS mode: only SunJSSE TrustManagers may be used");
}
if (tm[i] instanceof X509ExtendedTrustManager) {
return (X509TrustManager)tm[i];
} else {
return new AbstractTrustManagerWrapper(
(X509TrustManager)tm[i]);
}
}
}
// nothing found, return a dummy X509TrustManager.
return DummyX509TrustManager.INSTANCE;
}
exception occures in if (SunJSSE.isFIPS() &&
!(tm[i] instanceof X509TrustManagerImpl)) expression.
I suppose that tm[i] contains my DummyTrustManager , it can not be extended from X509TrustManagerImpl so my question is : How to disable Fips in SunJSSE ?
SunJSSE can be configured to run on FIPS-140 compliant mode as long as it uses a FIPS-140 certified cryptographic hardware or software provider that implements all cryptographic algorithms required by JSSE (ex. Network Security Services – NSS, Sun Cryptographic Accelerator 6000, nCipher, etc).
To enable FIPS mode, edit the file ${java.home}/lib/security/java.security and modify the line that lists com.sun.net.ssl.internal.ssl.Provider and associate the name of the FIPS-140 cryptographic provider (ex. SunPKCS11-NSS). The name of the provider is a string that concatenates the prefix SunPKCS11- with the name of the specified PKCS#11 provider in its configuration file.
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
SunPKCS11-NSS
In case of using NSS as cryptographic software token (Make use of NSS 3.1.1. or above), assuming the libraries are located under the /opt/nss/lib directory and its key database files (with the suffix .db) are under the /opt/nss/fipsdb directory, the sample configuration for representing NSS will be as follows:
# Use NSS as a FIPS-140 compliant cryptographic token
# SunPKCS11-NSS
name = NSS
nssLibraryDirectory = /opt/nss/lib
nssSecmodDirectory = /opt/nss/fipsdb
nssModule = fips
In FIPS mode, SunJSSE will perform SSL/TLS 1.0 based communication and cryptographic operations including symmetric and asymmetric encryption, signature generation and verification, message digests and message authentication codes, key generation and key derivation, random number generation, etc.
To anyone having a giant headache when you need to install a tomcat webapp on a third party server, I lost 1 hour trying to bypass this damn thing...
I solved in this way, without touching anything in the webapp.
Add this java parameter:
-Djava.security.disableSystemPropertiesFile=true
Source:
https://access.redhat.com/documentation/en-us/openjdk/8/pdf/configuring_openjdk_8_on_rhel_with_fips/OpenJDK-8-Configuring_OpenJDK_8_on_RHEL_with_FIPS-en-US.pdf
Also, if the app needs to connect to a Windows Server, you might want to disable FIPS there too:
In Control Panel, click Administrative Tools -> Local Security Policy.
In Security Settings -> Local Policies -> Security Options.
Under Policy in the right pane, double-click System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing, and then click Disabled.
Reboot the server
(bonus)
If you want to uninstall FIPS from the server, follow this giude (I didn't test it):
https://www.bggofurther.com/2021/02/disable-fips-mode-on-centos-7/