Intel® Business Client Software Development
Support for Intel® vPro™ software development and technologies associated with Intel vPro platforms.
1380 Discussions

Need help on calling the CertStoreAddKey webservice

peri
Beginner
545 Views

Hi All,

I am trying to provision the iAMT device in PKI TLS Mutual Authentication mode through a sample java provisioning server code written using Axis 1.3 stubs. After the provisioning, I am seeing in the management console that it receives the self-signed certificate from the iAMT device for the TLS mutual authetication, not the one that i have set through certStoreAddCertificate, certStoreAddKey and setTLSCredentials webservice calls. When i debugged it further, certStoreAddKey returned the status 0x80E(PT_STATUS_INVALID_KEY) while provisioning. I think this is the issue. When i looked at the iAMT Network Interface guide, it looks we need to pass the private key in the encoded as DER PKCS#1 format. Could you please let me how to pass the private key in Java in this format? If you provide me java samples, it will be great.

Thanks,

Periyasamy

0 Kudos
10 Replies
Randal_T_Intel
Employee
545 Views

Hi Periyasamy

The Intel Wsman-Translator (http://www.intel.com/software/wsman-translator) has .NET/C# source code that does this in a file called KeyFormatter.cs. The wsman-translator source is publicly available and can be converted to Java.

Below is an example of how to do this in Java. First you need to load the private key from a Java Key store. This should result in a java.secutiry.key object. Since you created the certificate I assume you have access to the private key from whatever store you are using. Below is an example of loading the private key from a keystore that you might find useful.

java.security.KeyStore pfx = java.security.KeyStore.getInstance("pkcs12");

//example of opening up the key store (in this example its a pkcs12 file with a password of 123)

pfx.load(new java.io.FileInputStream(file), "123".toCharArray());

// Find the alias names in the keystore

// Note: key stores with one certificate and key will just have one alias

String alias=null;

for (java.util.Enumeration e = pfx.aliases(); e.hasMoreElements();) {

alias= e.nextElement().toString();

}

// get the certificate and private key from the store

java.security.cert.Certificate cert = pfx.getCertificate(alias);

String cerData = WsmanUtils.getBase64String(cert.getEncoded());

java.security.Key key = pfx.getKey(alias, "123".toCharArray());

Now lets convert the covert the java.security.Key object into a base64 encoded string that AMT will accept as an argument its soap commands. AMT expects the key in ASN.1 DER and can handle key sizes of 1535, 1024, or 2048. In order to compile this example you will need a base64 encoding routine. I cant warranty this Java covertionexample but have tested againstserveral keys. If you have any issues you can always look at the wsman-translator code as a reference.

// keyData will be our resulting string and key will be the java.security.key we are coverting

String keyData=null;

try {

//Get an instance of an RSA key factory

KeyFactory fact = java.security.KeyFactory.getInstance("RSA");

// get the RSA private key spec from the key object returned from the store

RSAPrivateCrtKeySpec spec = fact.getKeySpec(key, RSAPrivateCrtKeySpec.class);

// get RSA parameters

byte[] mod=spec.getModulus().toByteArray();

byte[] exp=spec.getPublicExponent().toByteArray();

byte[] p =spec.getPrimeP().toByteArray();

byte[] q = spec.getPrimeQ().toByteArray();

byte[] dp = spec.getPrimeExponentP().toByteArray();

byte[] dq = spec.getPrimeExponentQ().toByteArray();

byte[] d = spec.getPrivateExponent().toByteArray();

byte[] iq = spec.getCrtCoefficient().toByteArray();

// create a byte buffer to store the converted key

byte buffer[] = new byte[4096];

int index=7; // index will start above zero to leave some bytes at the beginning for header

Object params[] = {mod,exp,d,p,q,dp,dq,iq};

// loop through all parts of the key add each encoded byte to the buffer (ASN.1 encoded)

for (int i=0;i

byte param[] = (byte[])params;

buffer[index++]=(byte)2;

int len = param.length;

boolean pad = (param.length > 0x80) && (param[0] !=0);

if (pad) len++;

int sizeType=0;

if (len < 0x80)

sizeType = 0x80;

else if (len <= 0xFF)

sizeType = 0x81;

else if (len <= 0xFFFF)

sizeType = 0x82;

switch (sizeType) {

case 0x81:

buffer[index++]=(byte)sizeType;

buffer[index++]=(byte)len;

break;

case 0x82:

buffer[index++]=(byte)sizeType;

buffer[index++]= (byte)(len >>8);//len[1]

buffer[index++]=(byte)(len & 0x000000FF);//len[0]

break;

default:

buffer[index++]=(byte)len;

break;

}

if (pad)

buffer[index++]=(byte)0;

// copy the param

for (int j=0;j

buffer[index++]=param;

}

// private key header

buffer[4]=(byte)2;//tag

buffer[5]=(byte)1;//size

buffer[6]=(byte)0;//version

//set the header to handle different keysizes

if (index<256) {

buffer[1]=(byte)48;

buffer[2]=(byte)129;

index=index+3;

buffer[3]=(byte)index;

//file must be DWORD bock readable

while ((index % 8)>0) index++;

byte[] temp = new byte[index-1];

System.arraycopy(buffer, 1, temp, 0, temp.length);

buffer=temp;

}

else {

int len = index-4;

buffer[0]=(byte)48;

buffer[1]=(byte)130;

buffer[2]= (byte)(len >>8);//len[1]

buffer[3]=(byte)(len & 0x000000FF);//len[0]

while (index < 1190 && (index % 8)>0) index++;

byte[] temp = new byte[index];

System.arraycopy(buffer, 0, temp, 0, temp.length);

buffer=temp;

}

//TODO: add your own base64 encoding routine here

keyData=covertToBase64String(buffer);

}

catch (Exception e) {

//TODO: throw your own Key format exception or do error handing here

}

return keyData;

}

Hope this helps!

Randy

0 Kudos
peri
Beginner
545 Views

Hi Randal,

Thanks for your reponse !

I have tried with your sample to try to set the private key. But still the issue (PT_STATUS_INVALID_KEY)persists. Let me explain the flow that i follow to set the client certificate for the iAMT device.

1. Run the following command to keypair and CSR

keytool -genkey -keyalg RSA -keysize 1024 -alias iamt -keystore amtkeystore -storetype pkcs12 -storepass secret

keytool -certreq -keystore amtkeystore -alias iamt -file testreq -storetype pkcs12 -storepass secret

2. Using the testreq CSR, i have got the certificate for the iAMT device issued by our Enterprise CA

3. I have set the client certificate using certStoreAddCertificate soap method which return PT_STATUS_SUCCESS.

4. Then i used the sample that you have given me to encode the private key in ASN.1 DER format from the keystore (amtkeystore) and trying to set using certStoreAddKey method. But still i get PT_STATUS_INVALID_KEY error. I am using the Base64 encoding routine from the following link http://iharder.sourceforge.net/current/java/base64/

Please let me know i am missing anything in setting up the client certificate and also in which scerarios iAMT soap method throws PT_STATUS_INVALID_KEY error.

Code used to encode the private key:

String password = "secret";
String keyAlias = "iamt";
String keystoreFile = path+"C:\\amtcert\\keytool\\client\\pkcs12\\amtkeystore";
KeyStore myclientkeystore = KeyStore.getInstance("pkcs12");
myclientkeystore.load(new FileInputStream(keystoreFile), password.toCharArray());
Key key = myclientkeystore.getKey(keyAlias, password.toCharArray());
Certificate cert = myclientkeystore.getCertificate(keyAlias);

String myprivateString = convertBase64format(key);
KeyPairType keyPairType = new KeyPairType(new RSAKeyPairType(myprivateString.getBytes()));
secStub.certStoreAddKey(keyPairType, statusCode, keyPairHandle);

//convertBase64format utility method

private static String convertBase64format(Key key)
{
String keyData=null;

try
{

// Get an instance of an RSA key factory
KeyFactory fact = KeyFactory.getInstance("RSA");
// get the RSA private key spec from the key object returned from the store
RSAPrivateCrtKeySpec spec = fact.getKeySpec(key, RSAPrivateCrtKeySpec.class);
// get RSA parameters

System.out.println(spec.getModulus().toByteArray().length);

byte[] mod=spec.getModulus().toByteArray();
byte[] exp=spec.getPublicExponent().toByteArray();
byte[] p =spec.getPrimeP().toByteArray();
byte[] q = spec.getPrimeQ().toByteArray();
byte[] dp = spec.getPrimeExponentP().toByteArray();
byte[] dq = spec.getPrimeExponentQ().toByteArray();
byte[] d = spec.getPrivateExponent().toByteArray();
byte[] iq = spec.getCrtCoefficient().toByteArray();

// create a byte buffer to store the converted key
byte buffer[] = new byte[4096];
int index=7; // index will start above zero to leave some bytes at the beginning for header

Object params[] = {mod,exp,d,p,q,dp,dq,iq};
// loop through all parts of the key add each encoded byte to the buffer (ASN.1 encoded)
for (int i=0;i {

byte param[] = (byte[])params;
buffer[index++]=(byte)2;
int len = param.length;
boolean pad = (param.length > 0x80) && (param[0] !=0);
if (pad) len++;
int sizeType=0;

if (len < 0x80)
sizeType = 0x80;
else if (len <= 0xFF)
sizeType = 0x81;
else if (len <= 0xFFFF)
sizeType = 0x82;


switch (sizeType) {
case 0x81:
buffer[index++]=(byte)sizeType;
buffer[index++]=(byte)len;
break;
case 0x82:
buffer[index++]=(byte)sizeType;
buffer[index++]= (byte)(len >>8);//len[1]
buffer[index++]=(byte)(len & 0x000000FF);//len[0]
break;
default:
buffer[index++]=(byte)len;
break;
}

if (pad)
buffer[index++]=(byte)0;
// copy the param
for (int j=0;j buffer[index++]=param;

}



// private key header

buffer[4]=(byte)2;//tag

buffer[5]=(byte)1;//size

buffer[6]=(byte)0;//version

// set the header to handle different keysizes

if (index<256)
{

buffer[1]=(byte)48;
buffer[2]=(byte)129;
index=index+3;
buffer[3]=(byte)index;

// file must be DWORD bock readable

while ((index % 8)>0) index++;


byte[] temp = new byte[index-1];
System.arraycopy(buffer, 1, temp, 0, temp.length);
buffer=temp;

}
else
{

int len = index-4;

buffer[0]=(byte)48;

buffer[1]=(byte)130;



buffer[2]= (byte)(len >>8);//len[1]
buffer[3]=(byte)(len & 0x000000FF);//len[0]


while (index < 1190 && (index % 8)>0)
index++;

byte[] temp = new byte[index];

System.arraycopy(buffer, 0, temp, 0, temp.length);

buffer=temp;
}

// TODO: add your own base64 encoding routine here

keyData=covertToBase64String(buffer);

}

catch (Exception e) {
e.printStackTrace();

// TODO: throw your own Key format exception or do error handing here

}

return keyData;

}

public static String covertToBase64String(byte[] rawData) {
return Base64.encodeBytes(rawData);
}

Thanks,

Periyasamy

0 Kudos
Richard_B_Intel1
Employee
545 Views

Hi Periyasamy-

I just wanted to let you know we are looking into your issue.

0 Kudos
peri
Beginner
545 Views

Thanks a lot RB.

Regards,

Periyasamy

0 Kudos
Randal_T_Intel
Employee
545 Views

Periyasamy,

Comment out the following lines of codefrom the sample I gave you and thingssould start towork (the code needing commented out isalittle before the the base64 conversion)

while (index < 1190 && (index % 8)>0)

index++;

The code that needs commented out was to add DWORD padding to the output but appears not to be needed and is causing your issue.

Also, make sure your base64 encoding routine is not adding any carriage return line feeds in the output. Suns routines do this by default but you can suppress with a flag.

Attached are some sample pfx filesI used for testing the code. Test1 is a 1024 key and Test11 is a 2048 key. passwordstring for bothis "123".

Randy

0 Kudos
peri
Beginner
545 Views

Hi Randy,

unfortunately the changes suggested by you doesn't solve the problem. Still i get PT_STATUS_INVALID_KEY error. I am following the steps given in the Reply # 2 for creating certs and passing into iAMT webservice. Could you please verify whatever i have done is valid or not?

Thanks,

Periyasamy

0 Kudos
RBens2
Valued Contributor I
545 Views

Hi Periyasamy,

I would suggest that you use the Setup and Configuration Application that comes with the SDK to provision your units. Plug your certs into the SCA at the appropriate folders with the appropriate names, and make sure that there's nothing wrong with your certs; then look into translating the code into Java. I've used the SCA many times and I know that it works. The SCA generates demo certs for testing with mutual authentication, and it has code that shows how to send the certs to the AMT system. So, use the SCA as a template for your Java code.

Regards,

Roger

0 Kudos
peri
Beginner
545 Views

Hi Roger,

Thanks for your inputs. I have tried to use our certs in the SCA sample, but it throws same (PT_STATUS_INVALID_KEY) error while setting up the private key.

As SCA expects the private key in the pem format, i have used the following code to export the private key in pem format from the keystore.


package com.test.iamt.provisioning;


import sun.misc.BASE64Encoder;
import java.security.cert.Certificate;
import java.security.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;

class ExportPrivateKey {
public static void main(String args[]) throws Exception{
ExportPrivateKey myep = new ExportPrivateKey();
myep.doit();
}

public void doit() throws Exception{

KeyStore ks = KeyStore.getInstance("pkcs12");
String fileName = "C:\\zcmcert\\keytool\\client\\pkcs12\\amtkeystore";

char[] passPhrase = "secret".toCharArray();
BASE64Encoder myB64 = new BASE64Encoder();


File certificateFile = new File(fileName);
ks.load(new FileInputStream(certificateFile), passPhrase);

KeyPair kp = getPrivateKey(ks, "iamt", passPhrase);

PrivateKey privKey = kp.getPrivate();


String b64 = myB64.encode(privKey.getEncoded());
FileWriter writer = null;
writer = new FileWriter("newkey.pem");
writer.write("-----BEGIN RSA PRIVATE KEY-----"+"\n");
writer.write(b64);
writer.write("\n");
writer.write("-----END RSA PRIVATE KEY-----");

writer.close();

}

public KeyPair getPrivateKey(KeyStore keystore, String alias, char[] password) {
try {
// Get private key
Key key = keystore.getKey(alias, password);
if (key instanceof PrivateKey) {
// Get certificate of public key
Certificate cert = keystore.getCertificate(alias);

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

// Return a key pair
return new KeyPair(publicKey, (PrivateKey)key);
}
} catch (UnrecoverableKeyException e) {
} catch (NoSuchAlgorithmException e) {
} catch (KeyStoreException e) {
}
return null;
}

}


It looks there is some issue related cert that we generated. As i already mentioned i am following steps given in the Reply #2 for generating certificates. can you verify the keytool command that i use is valid?

Or Do i miss something while exporting private key from java keystore into the pem format?

Thanks,

Periyasamy

0 Kudos
peri
Beginner
545 Views

Hi All,

Now i have seen certStoreAddKey works fine with the private key that is generated from keytool command.

The following workarounds fixed the issue

1. Generated the keypair using the following keytool command

keytool -genkey -v -alias iamt -keyalg RSA -storetype PKCS12 -keystore test.p12 -dname "CN=blramttest.bl
r.novell.com" -storepass secret

2. By passing Base64 bytes of encoded private key as the input for certStoreAddKey.

Thanks a lot for your help.

Thanks,

Periyasamy

0 Kudos
Lance_A_Intel
Employee
545 Views

Happy your code is working now.

Thanks for sharing how you resolved it.

0 Kudos
Reply