3

I have created and downloaded a certificate from sales force, as per the instructions in PicketLink document.

I downloaded the certificate and its name is mysample.crt and I imported the certificate into a keysotre.

keytool -import -file mysample.crt -keystore keystore.jks -alias salesforce-idp

To check, I exported the public key also

keytool -export -alias salesforce-idp -keystore keystore.jks -rfc -file public.cert

I have a Java code to get the Public Key, but it is not working. This is my Code

package com.sample.keystore;

import java.io.File;
import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.apache.commons.codec.binary.Base64;

public class ExtractPublicKey {

    public static void main(String[] args) {

        try {
            // Load the keystore
            File file = new File("/home/user/salesforce-cert/keystore.jks");
            FileInputStream is = new FileInputStream(file);
            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
            String alias = "salesforce-idp";
            String password = "user";
            char[] passwd = password.toCharArray();
            keystore.load(is, passwd);
            KeyPair kp = getKeyPair(keystore, alias, passwd);
            Base64 base64 = new Base64();
            PublicKey pubKey = kp.getPublic();

            String publicKeyString = base64.encodeBase64String(pubKey
                    .getEncoded());

            System.out.println(publicKeyString);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static KeyPair getKeyPair(KeyStore keystore, String alias, char[] password) throws Exception {
            // Get private key
            Key key = keystore.getKey(alias, password);
            if (key instanceof PrivateKey) {
                // Get certificate of public key
                java.security.cert.Certificate cert = keystore.getCertificate(alias);

                // Get public key
                PublicKey publicKey = cert.getPublicKey();

                // Return a key pair
                return new KeyPair(publicKey, (PrivateKey)key);
            }
        return null;
    }

}

But when I run the code, I get the following exception

java.lang.NullPointerException
    at com.sample.keystore.ExtractPublicKey.main(ExtractPublicKey.java:28)

Line 28 refers to PublicKey pubKey = kp.getPublic();. Because the method returns null instead of the Key Pair. Why is that? And how to get the Public Key?

UPDATE 1

I updated the code to

keystore.load(is, passwd);
PublicKey pubKey = keystore.getCertificate(alias).getPublicKey();
String publicKeyString = Base64.encodeBase64String(pubKey.getEncoded());
System.out.println(publicKeyString);

Then I am getting folowing Key

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlKJTbmfEumDR7nAfBbfAstuUvsgKxizZ1mwGc990dSsmgldIhsrLqpAECdf7vl2q2F8DyXciOopZbJPt/UBmpl6M1TJCQ34UyZaYGI2qid8jSNxFYGApfYPxIBJAk9YOAATqqyAREL+i1mUaFfN8WULFDvz6WsuXOjuxBobqjkg4TUumyyVgZda9ksl3aJmft02AfDMw/GCT8gKPTQb3nZP9BwTo5AQkV5fy0cKZ80G4qD+fiuZJ+8IecgFgXl5agZ0y2Wri8i1OGTGw34SUP2gOO+NUd17YA5AO+ocHlH8yzlXHNH7DPQsLo+Uz8CcXV+eLyzxGTGfuiTw8qsPCCwIDAQAB

Nut actual key is different. In public,cert, the key is different from what I am getting through Java code.

2 Answers2

1

To get the certificates associated with a private key, you should be calling getCertificateChain(), and using the zeroth element of the returned array. Not getCertificate().

user207421
  • 305,947
  • 44
  • 307
  • 483
  • When I do *keytool -list -keystore keystore.jks*, it shows as **trustedCertEntry** instead of **PrivateKeyEntry**. Is that a problem? –  Nov 03 '14 at 08:55
  • `getCertificateChain()` returns null –  Nov 03 '14 at 09:00
  • Then you built the KeyStore wrongly. You must import the signed certificate using the same alias as you used to create the private key. You didn't. Check the instructions you linked. – user207421 Nov 03 '14 at 09:08
  • In salesforce, there is an option to create self signed certificate. We need to provide a label and unique name only. I am using the same name as alias name also. And I am getting the same NullPointerException. –  Nov 03 '14 at 09:20
  • Check again. You didn't use the alias in the instructions you cited. You used `salesforce-idp`, which is not what it says there. – user207421 Nov 03 '14 at 09:22
  • Sorry I don't get it. I given a unique name. And I am using the same name as alias name also. Did I miss anything there? –  Nov 03 '14 at 09:37
  • Impossible to say. If you're claiming you followed the instructions exactly, you didn't, because you used a different alias. If you're claiming you used the same alias as you did when you created the keypair, it's unverifiable, as you haven't posted the command you used to create the keypair. – user207421 Nov 05 '14 at 00:46
  • getCertificate() and getting the first (zero) certificate from the chain is the same. See JavaDoc: https://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.html#getCertificate(java.lang.String) "If the given alias name identifies an entry created by a call to setKeyEntry, or created by a call to setEntry with a PrivateKeyEntry, then the first element of the certificate chain in that entry is returned." – Darrell Teague Mar 16 '16 at 20:11
0

What about

keystore.load(is, passwd);
PublicKey pubKey = keystore.getCertificate(alias).getPublicKey();
String publicKeyString = Base64.encodeBase64String(pubKey.getEncoded());

Edit

After being downvoted, here some more detail how I see it:

The OP provided this link: https://docs.jboss.org/author/display/PLINK/Picketlink+as+SP,+Salesforce+as+IDP?_sscc=t where it says:

After certificate will be generated in Salesforce, you can download it to your computer.

and

This certificate will be used to sign SAMLResponse messages sent from Salesforce IDP.

Type self-signed

after that, OP is told to import that cert, from which he would now like to retrieve the public key:

keytool -import -file salesforce_idp_cert.cer -keystore jbid_test_keystore.jks -alias salesforce-idp

So it seems obvious that

  • OP does not have the private key for that cert
  • There is no chain for this cert
Community
  • 1
  • 1
pma
  • 860
  • 1
  • 9
  • 26
  • Please see the **UPDATE 1**. The key I am getting is different from the actual private Key –  Nov 03 '14 at 08:05
  • 1
    How did you do the comparison? keytool -export exports the certificate, not only the public key. Maybe download and use the keystore-explorer if you are on Windows. – pma Nov 03 '14 at 08:18
  • The export command created a public.cert file with the public key. When I did *cat public.cert*, it showed the public key. And when I checked both are different. –  Nov 03 '14 at 08:21
  • 1
    I believe _cat_ show "------BEGIN CERTIFICATE----" instead of "----BEGIN PUBLIC KEY------". See the docu about export here: http://docs.oracle.com/javase/tutorial/security/toolsign/step5.html. To get the public key out of that file see this: http://stackoverflow.com/questions/10103657/how-to-print-the-public-key-of-a-certificate-using-keytool – pma Nov 03 '14 at 08:31
  • Still it is the public key –  Nov 03 '14 at 09:06
  • 1
    The public key is only part of it. Because of the other fields, the Strings you are comparing do not match – pma Nov 03 '14 at 09:13
  • I am not comparing with Java code. The string in the Java code I am getting is starting with **MIIBIjANBgkqhkiG9** but when I check the public key in the file it starts like **MIIeJGsddf9** something like this. Totally different. –  Nov 03 '14 at 09:34
  • So you did the accepted answer of this http://stackoverflow.com/questions/10103657/how-to-print-the-public-key-of-a-certificate-using-keytool on your public.cert and got MIIeJGsddf9...? – pma Nov 03 '14 at 10:14