adam_j_bradley1 Absent Member.
Absent Member.
729 views

Q: Retrieving users public key over LDAP

Is there any way to extract a public pki key over ldap and
use it to sign a document?

Looking for a generic solution that will let me dynamically
retrieve the public key from a certificate and use java to
digitally sign a text string.

Regards,
Adam
Labels (1)
0 Likes
9 Replies
adam_j_bradley1 Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

I'm currently trying the following code (which is failing and reports 0
certificates in the certs collection).

LDAP dstrace trace screen (below) indicates the ldapsearch is returning
the attribute "userCertificate:binary". Ethereal dump available from
http://www.identityconcepts.com.au/files/ldapkeysearch.eth
..
Anyone have a code sample that does this?

Thanks in advance!
Adam

---snip---
if (_keyStoreType == "LDAP") {
LDAPCertStoreParameters params = new
LDAPCertStoreParameters( _keystorePath, 389);

X509CertSelector xcs = new X509CertSelector();

xcs.setSubject(_alias);

CertStore store = CertStore.getInstance("LDAP", params
);
Collection certs = store.getCertificates(xcs);

System.out.println(certs.size());
Iterator i = certs.iterator();

while (i.hasNext())
{
X509Certificate cert = (X509Certificate) i.next();
System.out.println(cert);
}
}
---snip---

For which I receive

---snip---
19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) DoBind on
connection 0x8324790
19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) Treating simple
bind with empty DN and no password as anonymous
19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) Bind name:NULL,
version:3, authentication:simple
19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) Sending
operation result 0:"":"" to connection 0x8324790
19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) DoSearch on
connection 0x8324790
19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) Search request:
base: "CN=admin,O=services"
scope:0 dereference:3 sizelimit:0 timelimit:0 attrsonly:0
filter: "(objectClass=*)"
attribute: "crossCertificatePair;binary"
attribute: "cACertificate;binary"
attribute: "authorityRevocationList;binary"
attribute: "userCertificate;binary"
19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) Sending search
result entry "cn=admin,o=services" to connection 0x8324790
19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) Sending
operation result 0:"":"" to connection 0x8324790
---snip---
0 Likes
Anonymous_User Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

Here is some code that should point you int he right direction.
It is NOT JNDI, but if you can retrieve the attribute values you should
be able to get the ideas.
Ignore the references to MonitorException (just some custom exception we
used)

-jim

/**
* This does not work. I can not throw an exception in a loop and let
the loop continue.
* Need to do the loop from the schedule and let checkThisCertificate
throw.
* @param ldc LDAPConnection - connection to server
* @param baseDN String - baseDN in tree to look
* @param alertIntervalDays long - If expires in this number of days,
alert
* @throws com.novell.ldap.LDAPException
* @throws com.willeke.ldap.LDAPmonitor.MonitorException -
*/
public static void checkCerts( LDAPConnection ldc, String baseDN,
long alertIntervalDays )
throws LDAPException, MonitorException
{
String attr[] =
{"caCertificate", "nDSPKIPublicKeyCertificate"};
//alertIntervalDays = 90;
LDAPSearchResults searchResults = ldc.search( baseDN,
LDAPConnection.SCOPE_ONE, "(nDSPKIPublicKeyCertificate=*)",
attr, false );
// fdg
while( searchResults.hasMore() )
{
LDAPEntry nextEntry = null;
try
{
nextEntry = searchResults.next();
}
catch( LDAPException e )
{
logger.debug( "SearchBase of: " + baseDN + " " + e.getMessage() );
//System.out.println( "Error: " + e.toString() );
// Exception is thrown, go for next entry
continue;
}
String entryDN = nextEntry.getDN();
String methodID = "checking Certificate: " + entryDN;
logger.debug( methodID );
LDAPAttributeSet attributeSet = nextEntry.getAttributeSet();
String issuerDN = "unknown";
Iterator allAttributes = attributeSet.iterator();
while( allAttributes.hasNext() )
{
LDAPAttribute attribute = ( LDAPAttribute )allAttributes.next();
try
{
checkThisCert( attribute );
}
catch( MonitorException ex )
{
logger.error( methodID + " " + ex.getMessage() );
throw new MonitorException( methodID + " " + ex.getMessage() );
}
} // while attributes
} // while more entries
}

/**
*
* @param certAttr LDAPAttribute
* @throws com.willeke.ldap.LDAPmonitor.MonitorException
*/
public static void checkThisCert( LDAPAttribute certAttr )
throws MonitorException
{
String attributeName = certAttr.getName();
byte[] allValues = certAttr.getByteValue();
CertificateFactory cf = null;
Collection c = null;
try
{
cf = CertificateFactory.getInstance( "X.509" );
c = cf.generateCertificates( new ByteArrayInputStream( allValues ) );
}
catch( CertificateException ex1 )
{
throw new MonitorException( "Unable to Read Certificate" );
}

Iterator it = c.iterator();
while( it.hasNext() )
{
X509Certificate cert = ( X509Certificate )it.next();
try
{
cert.checkValidity();
}
catch( CertificateNotYetValidException ex )
{
String mex = " Is NOT VALID! " + ex.getMessage();
throw new MonitorException( mex );
}
catch( CertificateExpiredException ex )
{
String mex = " Is NOT VALID! " + ex.getMessage();
throw new MonitorException( mex );
}
java.util.Date expires = cert.getNotAfter();
GregorianCalendar calNow = new GregorianCalendar();
GregorianCalendar calExp = new GregorianCalendar();
calExp.setTime( expires );
//issuerDN = cert.getIssuerDN().getName();
int daysTilExp = com.willeke.utility.DateUtils.daysPast( calExp );
long diffDays = com.willeke.utility.DateUtils.diffDayPeriods( calNow,
calExp );
if( diffDays <= 0 )
{
String mex = " Will expire in: " + diffDays + " days!";
throw new MonitorException( mex );
}
}
}


Adam Bradley wrote:
> I'm currently trying the following code (which is failing and reports 0
> certificates in the certs collection).
>
> LDAP dstrace trace screen (below) indicates the ldapsearch is returning
> the attribute "userCertificate:binary". Ethereal dump available from
> http://www.identityconcepts.com.au/files/ldapkeysearch.eth
> .
> Anyone have a code sample that does this?
>
> Thanks in advance!
> Adam
>
> ---snip---
> if (_keyStoreType == "LDAP") {
> LDAPCertStoreParameters params = new
> LDAPCertStoreParameters( _keystorePath, 389);
> X509CertSelector xcs = new
> X509CertSelector();
> xcs.setSubject(_alias);
> CertStore store =
> CertStore.getInstance("LDAP", params
> );
> Collection certs = store.getCertificates(xcs);
> System.out.println(certs.size());
> Iterator i = certs.iterator();
>
> while (i.hasNext())
> { X509Certificate cert =
> (X509Certificate) i.next();
> System.out.println(cert);
> } }
> ---snip---
>
> For which I receive
>
> ---snip---
> 19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) DoBind on
> connection 0x8324790
> 19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) Treating simple
> bind with empty DN and no password as anonymous
> 19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) Bind name:NULL,
> version:3, authentication:simple
> 19:21:44 B4783BB0 LDAP: (192.168.0.2:4436)(0x0001:0x60) Sending
> operation result 0:"":"" to connection 0x8324790
> 19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) DoSearch on
> connection 0x8324790
> 19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) Search request:
> base: "CN=admin,O=services"
> scope:0 dereference:3 sizelimit:0 timelimit:0 attrsonly:0
> filter: "(objectClass=*)"
> attribute: "crossCertificatePair;binary"
> attribute: "cACertificate;binary"
> attribute: "authorityRevocationList;binary"
> attribute: "userCertificate;binary"
> 19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) Sending search
> result entry "cn=admin,o=services" to connection 0x8324790
> 19:21:44 B1777BB0 LDAP: (192.168.0.2:4436)(0x0002:0x63) Sending
> operation result 0:"":"" to connection 0x8324790
> ---snip---

0 Likes
adam_j_bradley1 Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

Jim,

Thankyou for your post, the arrival of my 3rd child (and first daughter)
has slowed my progress 🙂

One last question, are you able to retrieve the User's public and
private keys with this method?
Thanks in advnance!

Adam
> Here is some code that should point you int he right direction.
> It is NOT JNDI, but if you can retrieve the attribute values you
> should be able to get the ideas.
>
> try
> {
> cf = CertificateFactory.getInstance( "X.509" );
> c = cf.generateCertificates( new ByteArrayInputStream( allValues
> ) );
> }
> catch( CertificateException ex1 )
> {
> throw new MonitorException( "Unable to Read Certificate" );
> }
>
> Iterator it = c.iterator();
> while( it.hasNext() )
> {
> X509Certificate cert = ( X509Certificate )it.next();
> try
> {
> cert.checkValidity();
> }

0 Likes
Anonymous_User Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

AFAIK, If the private key is present in the to the "X509Certificate
cert", the cert is a "real" cert that could be written to a file.

So if the private key is in there, and assuming you would know the
password to extract the private key, you should be able to do so.

-jim

Adam Bradley wrote:
> Jim,
>
> Thankyou for your post, the arrival of my 3rd child (and first daughter)
> has slowed my progress 🙂
>
> One last question, are you able to retrieve the User's public and
> private keys with this method?
> Thanks in advnance!
>
> Adam
>> Here is some code that should point you int he right direction.
>> It is NOT JNDI, but if you can retrieve the attribute values you
>> should be able to get the ideas.
>>
>> try
>> {
>> cf = CertificateFactory.getInstance( "X.509" );
>> c = cf.generateCertificates( new ByteArrayInputStream( allValues
>> ) );
>> }
>> catch( CertificateException ex1 )
>> {
>> throw new MonitorException( "Unable to Read Certificate" );
>> }
>>
>> Iterator it = c.iterator();
>> while( it.hasNext() )
>> {
>> X509Certificate cert = ( X509Certificate )it.next();
>> try
>> {
>> cert.checkValidity();
>> }

0 Likes
adam_j_bradley1 Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

Jim Willeke wrote:
> AFAIK, If the private key is present in the to the "X509Certificate
> cert", the cert is a "real" cert that could be written to a file.
> So if the private key is in there, and assuming you would know the
> password to extract the private key, you should be able to do so.

I can now retrieve the public key from the user Certificate (thankyou!)
but have no access to the private key over LDAP. In fact,
nowhere in any of the methods for the X509Certificate class is there any
mention of private key.

Only keystore provides access to the keypair, so the I'm back to trying
to use the LDAPCertStore methods.

---snip---
if (_keyStoreType == "LDAP") {
LDAPCertStoreParameters params = new
LDAPCertStoreParameters( _keystorePath, 389);
X509CertSelector xcs = new X509CertSelector();

xcs.setSubject(_alias);
CertStore store = CertStore.getInstance("LDAP", params );
Collection certs = store.getCertificates(xcs);

System.out.println(certs.size());
Iterator i = certs.iterator();

while (i.hasNext())
{
X509Certificate cert = (X509Certificate) i.next();
System.out.println(cert);
} }
---snip---

Adam
0 Likes
Anonymous_User Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

I have not attempted retrieving the privateKey from a certificate.
Have you looked at:
http://72.5.124.55/j2se/1.5.0/docs/api/javax/security/auth/x500/X500PrivateCredential.html
-jim



Adam Bradley wrote:
> Jim Willeke wrote:
>> AFAIK, If the private key is present in the to the "X509Certificate
>> cert", the cert is a "real" cert that could be written to a file.
>> So if the private key is in there, and assuming you would know the
>> password to extract the private key, you should be able to do so.

> I can now retrieve the public key from the user Certificate (thankyou!)
> but have no access to the private key over LDAP. In fact,
> nowhere in any of the methods for the X509Certificate class is there any
> mention of private key.
>
> Only keystore provides access to the keypair, so the I'm back to trying
> to use the LDAPCertStore methods.
>
> ---snip---
> if (_keyStoreType == "LDAP") {
> LDAPCertStoreParameters params = new
> LDAPCertStoreParameters( _keystorePath, 389);
> X509CertSelector xcs = new X509CertSelector();
> xcs.setSubject(_alias);
> CertStore store = CertStore.getInstance("LDAP", params );
> Collection certs = store.getCertificates(xcs);
>
> System.out.println(certs.size());
> Iterator i = certs.iterator();
>
> while (i.hasNext())
> {
> X509Certificate cert = (X509Certificate) i.next();
> System.out.println(cert);
> } }
> ---snip---
>
> Adam

0 Likes
adam_j_bradley1 Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

Jim Willeke wrote:
> I have not attempted retrieving the privateKey from a certificate.
> Have you looked at:
> http://72.5.124.55/j2se/1.5.0/docs/api/javax/security/auth/x500/X500PrivateCredential.html
>

I had a look at that but it would appear the Private key is not
available using any of those methods.

What I found was something which looks more promising! It would appear
that using the Novell Certificate Server Classes for Java allows me to
do a whole host of PKI related tasks including
retrieve a User's PKI keypair.

The Novell Certificate Classes for Java
(http://developer.novell.com/wiki/index.php/Ncsjava) depend on the
Novell Certificate Classes for C
(http://forge.novell.com/modules/xfmod/project/?ncslib) and a client
version of NICI. Version 1 of the C library requires the Novell Client
(and is deprecated
http://developer.novell.com/wiki/index.php/Novell_Certificate_Server_for_C_Version_1),
Version 2 doesn't. Naturally I wan't to use Version 2. The NCSJ are JNI
wrappers around the NCSC library but I think the JNI stubs are for
Version 1 (which has the client dependency).

I've asked the question of a couple of Novell staff so hopefully I get
the answer I'm looking for 🙂

FYI, currently when I try and initialise the library I receive the following

---snip---
Unable to load NPKIAPI - library could not be found
---snip---

with the following code
---snip---
....
....
import com.novell.security.japi.*;
import com.novell.security.japi.pki.*;
....
....
try {
NPKIAPI nc = new NPKIAPI();
nc.initialize();
nc.createContext();
nc.setTreeName("192.168.0.8");
nc.connectToIPAddress(0, (short) 0, _serverIP.getBytes());
nc.dsLogin(_alias, _password);
System.out.println("Info: " + nc.versionInfo());

System.out.print("trying to read Nick Names...");
int nrOfNickNames = nc.readAllNickNames(_alias);
System.out.println(" done.");
}catch (Exception e) {
log.fatal(e.toString());
---snip---

An NTFILEMON report reveals the file is loaded

---snip---
6711 3:53:55 PM javaw.exe:7036 QUERY INFORMATION
C:\WINDOWS\system32\npkiapi.dll SUCCESS Attributes: A
---snip---

So I get the feeling my suspicions are correct. Pity they don't include
the typelib information in the file I could have tried generating stubs!

Regards,
Adam

0 Likes
adam_j_bradley1 Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP

Adam Bradley wrote:
> Jim Willeke wrote:
>> I have not attempted retrieving the privateKey from a certificate.
>> Have you looked at:
>> http://72.5.124.55/j2se/1.5.0/docs/api/javax/security/auth/x500/X500PrivateCredential.html
>>

> I had a look at that but it would appear the Private key is not
> available using any of those methods.
>
> What I found was something which looks more promising! It would
> appear that using the Novell Certificate Server Classes for Java
> allows me to do a whole host of PKI related tasks including retrieve a
> User's PKI keypair.
>
> ---snip---
> Unable to load NPKIAPI - library could not be found
> ---snip---

Referring to the attached message, it would appear that a couple of
DLL's which didn't ship from the NCSC classes (running depends.exe helped)
I now believe I have all the files I require, but obviously there's
something else awry as I'm getting the following.

---snip---
Assertion: "SAL_InitCount && (mhp)"
File: sal_lmutex.cpp
Line: 50

Call Stack:
Call Stack:
---snip---

Most likely version incompatabilities.

FYI: I copied the following dll's which shipped with the NCSC

dclient.dll size/date 569,434/17.2.2005
npkiapi.dll size/date 827,473/28.6.2006
npkit.dll size/date 630,863/28.6.2006
sal.dll size/date 122,958/17.2.2005
ntls.dll size/date 827,392/23.6.2005

Adam


---snip---
andreyk@abgcard.ru wrote:
> Hi,
>
>> I have a question, the Novell Certificate Classes for Java (NCSJ)
>> depend on the Novell Certificate Classes for C (NCSC) and a client
>> version of NICI. Version 1 of NCSC requires the Novell Client and is
>> deprecated, Version 2 doesn't. Naturally I want to use Version 2.

> You should understand the difference between Novell Client for Win32
> and NICI for Win32. To use NCS for Java you must install NICI while
> Novell Client is not required. Also npki.jar depends on the following
> DLL's: dclient.dll, npkiapi.dll, npkit.dll, sal.dll They are included
> in Novell Certificate Server Libraries for C SDK. They should be
> copied somewhere in your Win32 search path. I copied them into
> C:\WINNT\System32 Moreover there should be one more DLL on the same
> search path. It is NTLS.DLL which is missed in NCSL for C. I took it
> from eDirectory 8.73SP8 running on Win2000 server. In my case DLL's
> were as follows:


Thanks for clarifying that for me.

> dclient.dll size/date = 307270/03.10.02
> npkiapi.dll size/date = 381010/30.03.04
> npkit.dll size/date = 237648/30.03.04
> sal.dll size/date = 57402/10.11.03
> ntls.dll size/date = 827392/23.06.05
>


Running "depends" over the the various dll's which shipped with the NCSC
I noted I was missing msvcrtd.dll and ntls.dll.

I've copied of the dll's which shipped with the NCSC

dclient.dll size/date 569,434/17.2.2005
npkiapi.dll size/date 827,473/28.6.2006
npkit.dll size/date 630,863/28.6.2006
sal.dll size/date 122,958/17.2.2005
ntls.dll size/date 827,392/23.6.2005


I'm currently receiving the following error

---snip---
Assertion: "SAL_InitCount && (mhp)"
File: sal_lmutex.cpp
Line: 50

Call Stack:
Call Stack:
---snip---


Any ideas?

0 Likes
adam_j_bradley1 Absent Member.
Absent Member.

Re: Q: Retrieving users public key over LDAP


> I'm currently receiving the following error
>
> ---snip---
> Assertion: "SAL_InitCount && (mhp)"
> File: sal_lmutex.cpp
> Line: 50
>
> Call Stack:
> Call Stack:
> ---snip---
>
> Any ideas?

It would appear that taking the files from an existing eDirectory
installation (for Windows) gives you the best results - the following
prototype code fragment works nicely.
Thanks to everyone for their help.

---snip---

try {
if (_alias == null)
_alias = "invaliduser";

if (_password == null)
_password = "invalidpassword";

if (_keystoreType == null)
_keystoreType = "PKCS12";

if (_keystoreType.endsWith("LDAP")) {
// Retrieve KeyPair using NCS libraries

int nrOfNickNames = 0;
NPKIAPI nc = null;

try {
nc = new NPKIAPI();
nc.initialize();
nc.createContext();
nc.setTreeName(_keystorePath);
nc.connectToIPAddress(0, (short) 0,keystorePath.getBytes());
nc.dsLogin(_alias, _password);

if (debug) {
log.debug("Info: " + nc.versionInfo());
log.debug("trying to read Nick Names...");
}
nrOfNickNames = nc.readAllNickNames(_alias);
if (debug)
log.info(" done.");
} catch (Exception e) {
log.fatal("Error initialising Novell PKI Services" +
e.toString());
}

if (nrOfNickNames != 1) {
log.fatal("User should have a single alias");
throw new Exception("User should have a single alias");
} else {

byte[] userKeyPair =
nc.exportUserKey(nc.nickName(0),_password,NPKIAPI.PKI_CHAIN_CERTIFICATE);
keyStore = KeyStore.getInstance("PKCS12");
InputStream is = new
ByteArrayInputStream(userKeyPair);
keyStore.load(is,
password);
}
}

// Process the KeyStore - tetrieve alias entry from keystore
Enumeration aliases = keyStore.aliases();
String alias = null;
int count = 0;
while (aliases.hasMoreElements()) {
alias = aliases.nextElement().toString();
count++;
}
// Should only be one entry
if (count != 1) {
if(!alias.trim().equals(_alias)) {
throw new Exception("Failed to find a alias for: " +
_alias);
}
}

try {
// Get private key
Key key = keyStore.getKey(alias, _password.toCharArray());
if (key instanceof PrivateKey) {
// Get certificate of public key
cert = keyStore.getCertificate(alias);
// Get public key
PublicKey publicKey = cert.getPublicKey();
return new KeyPair(publicKey, (PrivateKey) key);
}
} catch (UnrecoverableKeyException e) {
return null;
} catch (NoSuchAlgorithmException e) {
return null;
} catch (KeyStoreException e) {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
---snip---

Adam
0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.