What are the Object Attributes needed to generate KeyPairs from YubiKey with PKCS11? - yubico

My application wants to sign documents using YubiKey with PIV (PKCS11). I was able to Login to my YubiKey but When I try to generate KeyPairs, it throws this error.
"Method C_GenerateKeyPair returned CKR_ATTRIBUTE_VALUE_INVALID"
This is the code I have right now (C# .NET)
byte[] ckaId = session.GenerateRandom(20);
// Prepare attribute template of new public key
List<IObjectAttribute> publicKeyAttributes = new List<IObjectAttribute>();
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PUBLIC_KEY));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, false));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, #"TestApp"));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ENCRYPT, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VERIFY, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_WRAP, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODIFIABLE, false));
// Prepare attribute template of new private key
List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, #"TestApp"));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, ckaId));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SENSITIVE, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_DECRYPT, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_UNWRAP, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODIFIABLE, false));
// Specify key generation mechanism
IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_RSA_PKCS_KEY_PAIR_GEN);
// Generate key pair
IObjectHandle publicKeyHandle = null;
IObjectHandle privateKeyHandle = null;
session.GenerateKeyPair(mechanism, publicKeyAttributes, privateKeyAttributes, out publicKeyHandle, out privateKeyHandle);

There are a few changes that need to be made to get past all the errors. To help anyone that hits similar vague error messages in the future the thing that helped me the most here was setting the YKCS11_DBG environment variable so that error messages from the libykcs11 library get printed to stderr (the Yubico docs here aren't up to date in all sections but they mention the variable and a few other relevant things here https://developers.yubico.com/yubico-piv-tool/YKCS11/)
As for the changes in order:
CKA_ID should be the same for both the private and public key template, but has a finite set of allowed values (covered by the Yubico docs page, and in the source) so you can't just use 20 random bytes
CKA_MODIFIABLE is not a valid attribute for the public or private key templates (although the Yubico docs show it as a supported attribute)
CKA_MODULUS_BITS must be set to 2048 or 1024 for the public key in RSA mode source
So something like this ended up working for me:
// Prepare attribute template of new public key
List<IObjectAttribute> publicKeyAttributes = new List<IObjectAttribute>();
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PUBLIC_KEY));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, false));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, #"TestApp"));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, 2)); // 2 == Digital Signature cert
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ENCRYPT, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_VERIFY, true));
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_WRAP, true));
//publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODIFIABLE, false)); -- not allowed
publicKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODULUS_BITS, 2048)); // required to be 1024 or 2048 for RSA
// Prepare attribute template of new private key
List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_PRIVATE, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, #"TestApp"));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, 2)); // 2 == Digital Signature cert
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SENSITIVE, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_DECRYPT, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_SIGN, true));
privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_UNWRAP, true));
//privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_MODIFIABLE, false)); -- not allowed
Also since it looks like you're roughly following the pkcs11interop sample, note that if you call session.DestroyObject on the key handles then the cert gets deleted

Related

Invoking Xtext Generator via Language Server Protocol explicitly

I have a DSL project using Xtext together with the Language Server Protocol.
Now I want to trigger a Generator from the client (in my case VS Code) to be executed on the server.
Not automatically (I would know how to do that), but explicitly triggered by the user from a VS Code command.
I am aware of the IExecutableCommandService in Xtext and I know how to hook into it.
But I don't know how to retrieve the corresponding Resource from a given file path:
#Override
public Object execute(ExecuteCommandParams params, ILanguageServerAccess access, CancelIndicator cancelIndicator) {
if ("c4.generator.type".equals(params.getCommand())) {
// fileURI passed from client to the server
String fileURI = ((JsonPrimitive)params.getArguments().get(0)).getAsString();
// This is where I stuck
Resource resource = whatAPItoCallToRetrieveResourceFromFile(fileURI);
// Call the generator then
doGenerate(resource);
}
return "Unknown Command";
}
The use-case is the same as described in this blog: https://dietrich-it.de/xtext/2011/10/15/xtext-calling-the-generator-from-a-context-menu/
But the description is for Eclipse only (not using lsp).
If you already have the correct URI, you should be able to use XtextResourceSet to get access to the resource:
final XtextResourceSet rs = new XtextResourceSet();
final Resource r = rs.getResource(fileURI, true);
doGenerate(r);
otherwise you can get access to the Xtext index and iterate over all resources searching for the resource of interest, by using access.doReadIndex:
final XtextResourceSet rs = new XtextResourceSet();
final Function<ILanguageServerAccess.IndexContext, Boolean> func = (
ILanguageServerAccess.IndexContext ctxt) -> {
for (final IResourceDescription rd: ctxt.getIndex().getAllResourceDescriptions()) {
if(<check_rd>) {
Resource r = rs.getResource(rd.getURI(), true);
doGenerate(r);
}
}
return true;
};
access.doReadIndex(func);

SQL Server Column Encryption using Azure Key Vault and Spring Boot

I need to save the data in SQL server having column encryption using the Azure Key vault
#Bean
#Primary
public DataSource dataSource() throws SQLException {
KeyVaultClient client = new KeyVaultClient(keyVaultCredentialService);
String userName = client.getSecret(vaultURL, "spring-datasource-username").value();
String password = client.getSecret(vaultURL, "spring-datasource-password").value();
String url = "jdbc:sqlserver://test.database.windows.net;databaseName=encryption_demo;columnEncryptionSetting=Enabled;";
String driverClass = client.getSecret(vaultURL, "spring-datasource-driverClassName").value();
DataSource dataSource = DataSourceBuilder
.create()
.username(userName)
.password(password)
.url(url)
.driverClassName(driverClass)
.build();
SQLServerColumnEncryptionAzureKeyVaultProvider akvProvider = new SQLServerColumnEncryptionAzureKeyVaultProvider(clientId, clientKey);
Map<String, SQLServerColumnEncryptionKeyStoreProvider> keyStoreMap = new HashMap<String, SQLServerColumnEncryptionKeyStoreProvider>();
keyStoreMap.put(akvProvider.getName(), akvProvider); SQLServerConnection.registerColumnEncryptionKeyStoreProviders(keyStoreMap);
return dataSource;
}
application.properties
azure.keyvault.uri= ....
azure.keyvault.client-id= ...
azure.keyvault.client-key= ...
SQLServer table
CREATE TABLE [dbo].[Patients](
[id] [int] PRIMARY KEY NOT NULL,
[ssn] [varchar](max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NOT NULL,
[first_name] [varchar](max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL,
[last_name] [varchar](max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK_Auto1], ENCRYPTION_TYPE = Randomized, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL
)
GO
While saving the data in DB getting the error:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Internal error while encryption: Illegal key size
Download and install the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files. Be sure to read the Readme included in the zip file for installation instructions and relevant details on possible export/import issues.
If using the mssql-jdbc-X.X.X.jre7.jar or sqljdbc41.jar, the policy files can be downloaded from Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download.
If using the mssql-jdbc-X.X.X.jre8.jar or sqljdbc42.jar, the policy files can be downloaded from Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8 Download.
If using the mssql-jdbc-X.X.X.jre9.jar, no policy file needs to be downloaded. The jurisdiction policy in Java 9 defaults to unlimited strength encryption.
For more details, you could refer to this article.

XML Digitial Security - Hmac_SHA1

I need to create a digest value for the below input
<u:Timestamp u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<u:Created>2015-07-28T13:35:54Z</u:Created>
<u:Expires>2015-07-28T13:40:49Z</u:Expires>
</u:Timestamp>
so am passing the above value as a doc obj to the below code
public static void main(String[] args) throws Exception {
// Create a DOM XMLSignatureFactory that will be used to generate the
// enveloped signature
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
SecretKey signingKey = new SecretKeySpec("welcome1".getBytes(), "HMAC");
// Create a Reference to the enveloped document (in this case we are
// signing the whole document, so a URI of "" signifies that) and
// also specify the SHA1 digest algorithm and the ENVELOPED Transform.
Reference ref = fac.newReference
("#_0", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform
("http://www.w3.org/2001/10/xml-exc-c14n#", (TransformParameterSpec) null)),
null, null);
// Create the SignedInfo
SignedInfo si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.EXCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.HMAC_SHA1, null),
Collections.singletonList(ref));
// Instantiate the document to be signed
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc =
dbf.newDocumentBuilder().parse(new FileInputStream("C:/Users/Signed_Encryp/timestamp.txt"));
// Create a DOMSignContext and specify the DSA PrivateKey and
// location of the resulting XMLSignature's parent element
DOMSignContext dsc = new DOMSignContext
(signingKey, doc.getDocumentElement());
// Create the XMLSignature (but don't sign it yet)
XMLSignature signature = fac.newXMLSignature(si, null);
// Marshal, generate (and sign) the enveloped signature
signature.sign(dsc);
// output the resulting document
OutputStream os;
if (args.length > 1) {
os = new FileOutputStream(args[1]);
} else {
os = System.out;
}
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
}
which returning me a result as
<u:Timestamp xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" u:Id="_0">
<u:Created>2015-07-28T13:35:54Z</u:Created>
<u:Expires>2015-07-28T13:40:49Z</u:Expires>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
<ds:Reference URI="#_0">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>1X/3X+yCdJc0x3n8guQnlCFvX+s=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>R4ZrHvlvyGvvQYpojZWPgUgRRSw=</ds:SignatureValue>
</ds:Signature>
</u:Timestamp>
here am not confident that digest value is created using the input am passed, also signature is created inside the timestamp tag , is there any option available to create signature tag after the timestamp tag.
Please help
To check if the signature is over the data, simply change the data and use the same key. If the HMAC value changes then the hash clearly is over the data. When changing back it should return to the old value. Note that this is true for HMAC-SHA1, it may not be the case for all primitives (e.g. RSA-PSS).
Alternatively, if you're up to it, you can perform the canonicalization yourself and manually calculate the signature. Or try another implementation.
If u:Timestamp is the root element then you cannot put anything next to it, as XML only has a single root element. You have yourself indicated that the signature is placed at doc.getDocumentElement(). You can however create a detached signature. Now you know how it is called, you should be able to search for it.

DotNetOpenAuth - OpenId login to Google asks for confirmation every time

I'm using DotNetOpenAuth to login to my site using Google OpenId. Simple code, discussed many times before:
protected static readonly string ENDPOINT = "https://www.google.com/accounts/o8/id";
public void RequestAuthentication(string realm, Uri returnUrl) {
using (OpenIdRelyingParty openid = new OpenIdRelyingParty()) {
IAuthenticationRequest openRequest = openid.CreateRequest(ENDPOINT, realm, returnUrl);
var fr = new FetchRequest();
fr.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, true));
fr.Attributes.Add(new AttributeRequest(WellKnownAttributes.Preferences.TimeZone, false));
fr.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.FullName, true));
fr.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Alias, false));
fr.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Last, true));
fr.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.First, true));
openRequest.AddExtension(fr);
openRequest.RedirectToProvider();
}
}
This works, but every time Google asks confirmation to pass users' email to my web site, ignoring 'Remember my decision' checkbox!
I already tried to replace FetchRequest with ClaimsRequest (with AXFetchAsSregTransform) - no difference.
What I'm doing wrong?
Seems this is Google-side problem.
In my Google account under 'Безопасность' > 'Авторизация приложений и сайтов' ('Security' > 'Authorized sites and apps' ?) settings I removed my site's tokens (all repeating items), on next logon I again checked 'remember' on confirmation page and viola - all future logon to my site does not require confirmation.

How to store public/private key securely

Looking to store public/private key information securely on an iOS device. I know I want to store this in the KeyChain however I am not 100% sure what sort of attributes I need to populate in the SecRecord. I was going to do something like:
// private key
SecKeyChain.Add(new SecRecord(SecKind.Key)
{
Accessible = SecAccessible.AlwaysThisDeviceOnly,
KeySizeInBits = 512,
KeyClass = SecKeyClass.Private,
CanSign = true,
ValueData = privateKeyValue,
Account = publicKeyValue
});
Which would store the private key, then follow a similar approach for the public key replacing the Account attribute with a value unique to the user e.g. username. However, not sure if this is the right way to use this.
Does anyone have a good examples on how you would do this specifically for keys?
Decided to go with the following approach:
// store public key
SecKeyChain.Add(new SecRecord(SecKind.Key)
{
ApplicationLabel = userName,
Accessible = SecAccessible.AlwaysThisDeviceOnly,
KeySizeInBits = 512,
KeyClass = SecKeyClass.Public,
ValueData = NSData.FromString(publicKey)
});
// store private key
SecKeyChain.Add(new SecRecord(SecKind.Key)
{
ApplicationLabel = publicKey,
Accessible = SecAccessible.AlwaysThisDeviceOnly,
KeySizeInBits = 512,
KeyClass = SecKeyClass.Private,
CanSign = true,
ValueData = NSData.FromString(secretKey)
});
This means each public key is mapped to an individual user and each private key is mapped to a public key which allows me to store multiple user keys (rather than only storing current logged in users).
Seems to work ok, however, still not 100% sure it is the correct way to do this kind of thing so some clarification would be nice.

Resources