Java: Luna HSM Verify Sign using Public Key - public-key-encryption

Using Java API, I am trying to access Public key stored in Luna HSM. Even though I am able to print the corresponding public key label name, but when I am trying to get the public key, I am not able to get the reference to that public key. Here is the code snippet:
KeyStore ks = KeyStore.getInstance("Luna");
ks.load(null, null);
lunaProvider = ks.getProvider();
publicKey = (PublicKey) ks.getKey(alipayImpl.getHsmKeyStorePublicEntryName(), null);
// ****************************************************************************
// ** If the private keystore is not found, return original barcode string. **
// ****************************************************************************
if (publicKey == null) {
throw new Exception("Unable to acquire the Public Key " + alipayImpl.getHsmKeyStorePublicEntryName() + ", Hash will not be verified.");
}
// ***********************************************************
// ** Create a Signature Object and sign the encrypted text **
// ***********************************************************
Signature signatureObject = Signature.getInstance(alipayImpl.getAlipaySignAlgorithm(), lunaProvider);
signatureObject.initVerify(publicKey);
signatureObject.update(signedMessage
.getBytes(AlipayConstants.INPUT_CHARSET_VALUE));
isValidSign = signatureObject.verify(Base64.decode(hash));
I am logging to HSM properly. While Accessing Private Key, I didnt have any issues. Is there any restriction on Luna HSM that access to public key is given only through Certificates?
Thanks in advance.

The correct answer is >
LunaKey lk= LunaKey.LocateKeyByAlias("publicKeyName");
But it is advisable to make the key persistent before querying HSM.

Did you try something like this :
final KeyStore keyStore = KeyStore.getInstance("Luna");
keyStore.load(null, null);
final Certificate certificate = keyStore.getCertificate(alias);
if (certificate == null) {
throw new IllegalArgumentException(String.format("Certificate '%s' does not exists", alias));
}
final PublicKey publicKey = certificate.getPublicKey();
// TODO Working with the public key...

In Java keystore there is no PublicKeyEntry and that's the reason why you're not able to access your public key.
https://docs.oracle.com/javase/8/docs/api/java/security/KeyStore.Entry.html
Java's KeyStore.KeyEntry interface has three implementing classes.
PrivateKeyEntry
SecretKeyEntry
TrustedCertificateEntry.
Java expects you to get retrieve a public key out of your certificate. Sebastien Vanmechelen has given you the perfect example on how to do that.
If by any chance, your Luna HSM partition does not have a X509 certificate then using LunaKey is the only alternative.

Related

PEM certificate public key padding

I have a x509 certificate (PEM format) and I want to load it in Go so that I can extract the public key and the signature from it. Extracting the signature works fine, but when extracting the public key I get some padding + the public key.
Does anyone know why that padding is added and how I can remove it?
For example:
the public key is : 04acad3942581b4b1992586....
when extracting it in Go i get: 3076301006072a8648ce3d020106052b81040022036200[then pe public key]
The code looks like this:
pub_key_str := cert.RawSubjectPublicKeyInfo
pub_key_hex := hex.EncodeToString(pub_key_str)

Access to private keys of keychain on Mac OS X

I'm implementing an application for Windows/Mac OS X on C# that digitally signs files with a certificate. To do that I'm using BouncyCastle and iText libraries. On windows works perfectly without any special code. I can read the stored certificates on the machine using this code.
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 certificate in store.Certificates)
{
if (certificate.HasPrivateKey && certificate.NotAfter >= DateTime.Now)
{
// USE CERTIFICATE
}
}
The problem that I'm facing is the access to the certificates stored in the Keychain. Because I can get the information of the certificates, but not their private keys. I suppose that there should be a way to access that information (after a confirmation from the user to allow the access), but I can't see how.
My current implementation to get the information of the certificates is:
var query = new SecRecord(SecKind.Certificate)
{
MatchValidOnDate = DatetimeToNSDate(DateTime.Now),
CanSign = true,
};
var certList = Security.SecKeyChain.QueryAsRecord(query, 100, out var result);
foreach(var cert in certLis)
{
SecCertificate tempCertificate = new SecCertificate(cert);
X509Certificate2 certificateObj = tempCertificate.ToX509Certificate2();
}
This certificateObj is a valid X509 certificate but its privateKey is null.

How to add Ltv & CRL (offline) while injecting .p7s to a Pdf?

I inject p7s to a Pdf using code below:
PdfWriter pdfWriter = new PdfWriter("results/final1.pdf");
PdfDocument document = new PdfDocument(new PdfReader("results/prepared1.pdf"), pdfWriter, new StampingProperties().UseAppendMode());
Stream output = new FileStream("results/signed1.pdf", FileMode.Create);
ExternalInjectingSignatureContainer container2 = new ExternalInjectingSignatureContainer(_p7s);
List<byte[]> crlCollection = new List<byte[]>();
crlCollection.Add(File.ReadAllBytes(#"ks/mycrls.crl"));
PdfSigner.SignDeferred(document, "Signature1", output, container2);
Found this
I found this
I tried it as below:
ICrlClient clrClient = new CrlClientOffline(File.ReadAllBytes(#"ks/mycrls.crl"));
addLTV("results/signed1.pdf", "results/final1.pdf", null, clrClient, null);
I did not see the Ltv enabled?
but the result is: Revocation checks were not performed.
addLtv
public static void addLTV(String src, String dest, IOcspClient ocsp, ICrlClient crl, ITSAClient itsaClient)
{
PdfReader reader = new PdfReader(src);
PdfWriter writer = new PdfWriter(dest);
PdfDocument pdfDoc = new PdfDocument(reader, writer, new StampingProperties().UseAppendMode());
LtvVerification v = new LtvVerification(pdfDoc);
SignatureUtil signatureUtil = new SignatureUtil(pdfDoc);
IList<string> names = signatureUtil.GetSignatureNames();
String sigName = names[names.Count - 1];
PdfPKCS7 pkcs7 = signatureUtil.ReadSignatureData(sigName);
if (pkcs7.IsTsp())
{
v.AddVerification(sigName, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.NO);
}
else
{
foreach (var name in names)
{
v.AddVerification(name, ocsp, crl, LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL, LtvVerification.CertificateInclusion.YES);
v.Merge();
}
}
pdfDoc.Close();
}
ExternalInjectingSignatureContainer
internal class ExternalInjectingSignatureContainer :IExternalSignatureContainer
{
public ExternalInjectingSignatureContainer(byte[] signature)
{
Signature = signature;
}
public void ModifySigningDictionary(PdfDictionary signDic)
{
}
public byte[] Sign(Stream data)
{
return Signature;
}
public byte[] Signature;
}
I want to improve it by adding the CRL Info (Offline), I have created a .crl file but I don't know how to add the crl while injecting .p7s?
TimeStamp
I know this is not related to this question, but after this I will add a timestamp to the signature, where can I find free timestamp (for development purpose)?
any help would be appreciated..
many thanks in advance
Don
How to add Ltv & CRL (offline) while injecting .p7s to a Pdf?
This depends on the profile of the PDF signatures you create and the capabilities of the validators.
PKCS#7 Signatures as used in ISO 32000
The PDF standard, ISO 32000 both in part 1 and part 2, in section 12.8.3.3 ("PKCS#7 Signatures as used in ISO 32000" / "CMS (PKCS #7) signatures") defined a profile for CMS signatures in PDFs.
This profile requires Revocation information to be included in the CMS container as an signed attribute.
Judging by your previous questions, you create the CMS signature container itself externally. To embed CRLs according to this profile, therefore, you have to update your external code producing the CMS container or (if some service not implemented by you creates those signatures) ask the signature creation service provider to update their code producing the CMS container to include the CRL in a signed attribute as detailed in ISO 32000 section 12.8.3.3.2 ("Revocation Information" / "Revocation of CMS-based signatures").
CAdES signatures as used in PDF
ETSI originally in TS 102 778, updated in EN 319 142, defined profiles (PAdES profiles) for CAdES signatures in PDFs. CAdES is a special profile of CMS. A rundown of these profiles has been copied into the updated PDF specification ISO 32000-2, section 12.8.3.4 ("CAdES signatures as used in PDF").
These profiles require revocation information to be embedded in an incremental update after the signed revision in a Document Security Store structure of PDF objects.
To embed CRLs according to these profiles, therefore, you take the signed PDF and add the CRL afterwards. This essentially is what your addLTV example does.
Why Revocation checks were not performed
In comments you mention that you use PAdES and add the CRL using your addLTV example but that Adobe Reader tells you that "Revocation checks were not performed."
If you read the text underneath that message, the cause becomes clear:
The selected certificate does not chain up to a certificate designated as trusted anchor (see the Trust Tab for details). The result is that revocation checks were not performed on this certificate.
If your validator cannot trace your signer certificate back (in a certificate chain) to a certificate it explicitly trusts, validation stops with an unknown validity. Revocation checks only make sense if the validator trusts the issuer of the signer certificate (directly or indirectly); only in this case of trust by issuer the validator needs to verify whether the issuer revoked the certificate.

How to load .keystore with multiple certs in SpringBoot

I am developing Spring Boot Application v2.0. From my Spring Boot App I am sending SOAP Request to get data from Soap WS. I have multiple Soap Request to different Soap Web Services. Every Soap WS has it's own certificate. I used Apache CXF v3.2.4 to auto generate "ws client" classes and everything else for WS.
Certificates are in PFX format. I have successfully create keystore via keytool. I tried to set up ssl.keyStore with this code ( also this is not a good way to set up these values, I assume it's better to do it in application-properties...:
System.setProperty("javax.net.ssl.keyStore","path to my keystore");
System.setProperty("javax.net.ssl.keyStorePassword", "mypassword");
I have 3 different certs in my keystore. All of them are tested separately and all of them works fine if they are only one in keystore. Problem is that when I have for example 3 certs in keystore, only first on the list is loaded.
I read multiple articles on Internet, this article was most interesting but unfortunately it didn't solve my problem (Registering multiple keystores in JVM) .
If I go through certs chain by alias I can see all certificates in the Console.
String storename = "C:/Certificates/mykeystore.ks";
char[] storepass = "mypassword".toCharArray();
String alias = "myalias";
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(storename), storepass);
java.security.cert.Certificate[] cchain = ks.getCertificateChain(alias);
List mylist = new ArrayList();
for (int i = 0; i < cchain.length; i++) {
mylist.add(cchain[i]);
}
CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertPath cp = cf.generateCertPath(mylist);
System.out.println(cp);
Do you have any suggestion?! What should I do in order to achieve stage that I can either load one keystore with multiple certificates or anything that will work?
Thanks in advance.
p.s. Also I tried to put these certs in jdk/jre/lib/security/cacerts via Portecle but no effect.
For each Web Service, I think you should handle the keystores (and/or truststores) separately and to be configured in the application.properties file. Below is a workable example of instantiating a SocketFactory for the Url Connection with the specific sets of certificate(s).
application.properties
keystore1.Path = src/main/resources/jks/yourKeyStoreFile1
keystore1.Password = keystore1pwd
truststore1.Path = src/main/resources/security1/cacerts
truststore1.Password = truststore1pwd
keystore2.Path = src/main/resources/jks/yourKeyStoreFile2
keystore2.Password = keystore2pwd
truststore2.Path = src/main/resources/security2/cacerts
truststore2.Password = truststore2pwd
When you are consuming different WebService, use a different SocketFactory. Below is a sample of .p12 keystore plus a .jks truststore (cert). You could easily convert the type of certificate into different format.
#Component
public class MySocketFactory {
#Value("${keystore1.Path}")
String keystore1Path;
#Value("${keystore1.Password}")
String keystore1Password;
#Value("${truststore1.Path}")
String truststore1Path;
#Value("${truststore1.Password}")
String truststore1Password;
public MySocketFactory() {
}
public SSLSocketFactory getSocketFactory() {
try {
SSLContext context = SSLContext.getInstance("TLS");
KeyManagerFactory keyMgrFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");
char[] keyStorePassword = keystore1Password.toCharArray();
keyStore.load(new FileInputStream(keystore1Path), keyStorePassword);
keyMgrFactory.init(keyStore, keyStorePassword);
TrustManagerFactory trustStrFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance("JKS");
char[] trustStorePassword = truststore1Password.toCharArray();
trustStore.load(new FileInputStream(truststore1Path), trustStorePassword);
trustStrFactory.init(trustStore);
context.init(keyMgrFactory.getKeyManagers(), trustStrFactory.getTrustManagers(), null);
return context.getSocketFactory();
} catch (Exception e) {
System.err.println("Failed to create a server socket factory...");
e.printStackTrace();
return null;
}
}
}
Create the same for the second SocketFactory. Hope this helps.

Importing a Private Key to Keychain returns EINVAL error

I am trying to import RSA private keys into the keychain using my application. The first time I import a key using SecKeychainImport() the operation is successful, a subsequent import gives me an EINVAL (100022) error.
This does not happen if I quit and relaunch the app between two imports. I am including the source code below.
CFArrayRef array = (CFArrayRef)[NSMutableArray array];
SecExternalFormat format = kSecFormatUnknown;
//We are always storing a private key…
SecExternalItemType type = kSecItemTypePrivateKey;
SecKeyImportExportParameters params;
SecKeychainRef keychain;
SecKeychainCopyDefault(&keychain);
memset(&params, 0, sizeof(params));
params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
params.flags = kSecKeyNoAccessControl;
params.keyUsage = CSSM_KEYUSE_ANY;
params.keyAttributes = CSSM_KEYATTR_EXTRACTABLE;
err = SecKeychainItemImport((CFDataRef)data,
(CFStringRef)#"pem",
&format,
&type,
0,
NULL,
keychain,
&array);
if(err == noErr)
{
//Change the kSecKeyPrintName attribute of the keychain item.
}
else
{
//Handle the error by displaying appropriate alert.
}
Am I missing anything obvious?
Try setting the CSSM_KEYATTR_PERMANENT bit in params.keyAttribute. On Lion, I can import multiple PEM-armoured RSA private keys (generated with openssl genrsa) into a keychain if I explicitly set this attribute. If I don't, I get errSecItemNotFound (-25300) when importing the very first key.
(Don't forget to remove kSecKeyNoAccessControl before deploying this code in production. Also, if you generate the key yourself, consider using SecKeyGenerate/SecKeyGenerateSymmetric instead.)

Resources