I'm stuck in creating correctly PKCS#10 certificate signing request and HMAC seal. I need to create them and send to remote service that will produce for me certificate in PKCS#7 format. More exactly:
Create a key pair for certificate and generate PKCS#10 request
(private key is never sent to the remote service)
use: key length 1024bit, SHA-1 algorithm, DER –encoded
Subject info: CN=name, serialNumber=userID, C=country (as above)
Create HMAC seal
use DER coded PKCS#10 above as input
SMS-activation code as the key (10-digits)
I'm wrapping the result into SoapMessage and sending to remote service and get a response. The response is error because either CSR or HMAC were generated incorrectly. The remote service doesn't send more specific error message, but as I said the error is because of my incorrectly generated CSR or HMAC. The subject and HMAC key are example values given by remote service, that's why the issue can't be because of them.
Here is the code how I implemented it
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
public class CustomerCert {
private final KeyPairGenerator keyGen;
private final KeyPair keypair;
private final PublicKey publicKey;
private final PrivateKey privateKey;
private final byte[] pkcs10;
private HMac hmac;
private byte[] hmacBytes;
public CustomerCert(String company, String userId, String country)
throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException {
keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024, new SecureRandom());
keypair = keyGen.generateKeyPair();
publicKey = keypair.getPublic();
privateKey = keypair.getPrivate();
pkcs10 = this.generatePKCS10(company, userId, country);
}
private byte[] generatePKCS10(String company, String userId, String country) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
String sigAlg = "SHA1withDSA";
String params = "CN=" + company + ", serialNumber=" + userId + ", C=" + country;
X500Principal principal = new X500Principal(params);
PKCS10CertificationRequest kpGen = new PKCS10CertificationRequest(sigAlg, principal, publicKey, new DERSet(), privateKey, null);
byte[] c = kpGen.getEncoded();
return c;
}
public String getCSRasString() throws UnsupportedEncodingException {
return new String(pkcs10, "ASCII"); // ISO-8859-1
}
public byte[] createHMacSeal(byte[] message, String key) throws UnsupportedEncodingException
{
hmac = new HMac(new SHA1Digest());
hmacBytes = new byte[hmac.getMacSize()];
{
hmac.init(new KeyParameter(Hex.decode(key)));
hmac.update(message, 0, message.length);
hmac.doFinal(hmacBytes, 0);
}
return hmacBytes;
}
}
What I am not sure is how according to the requirement make the PKCS request DER encoded?
Another question is how to give to hmac seal a DER coded pkcs input?
And lastly how to get the byte array of generated HMAC seal, because the remote service requires it as base64 encoded byte array?
EDIT
As @Jcs pointed out my PKCS creation is correct but right now I'm not sure about the correct HMAC creation. I got now beter response from remote server and the error message I get now is error in MAC value
.
My current methods for HMac creation are following:
public byte[] createHMacSeal(byte[] message, String key) {
String messageString = new String(message, "US-ASCII");
HMac hmac = new HMac(new SHA1Digest());
byte[] resBuf = new byte[hmac.getMacSize()];
{
byte[] m = messageString.getBytes();
if (messageString.startsWith("0x"))
{
m = Hex.decode(messageString.substring(2));
}
hmac.init(new KeyParameter(key.getBytes("US-ASCII")));
hmac.update(m, 0, m.length);
hmac.doFinal(resBuf, 0);
hmacBytes = resBuf;
}
return hmacBytes;
public byte[] createHMacSeal(byte[] message, String key) {
SecretKey secretKey = new SecretKeySpec(key.getBytes("US-ASCII"), "HMac-SHA1");
Mac mac;
mac = Mac.getInstance("HMac-SHA1", "BC");
mac.init(secretKey);
mac.reset();
mac.update(message, 0, message.length);
hmacBytes = mac.doFinal();
return hmacBytes;
}
These two methods return different values for HMAC. For the method arguments byte[] message
is the DER coded PKCS getPKCS10()
and second argument key
is the SMS activation code as a 10 character string 1234567890
. Now I'm really struck and have tried many different possibilities but still the same error message from the remote server.