How to store Public Certiticate (.cer file) in Azure Key Vault - azure-keyvault

How I can upload or store public key (.cer) file in azure keyvault. From the keyvault panel it gives error when I tried to to upload any .cer file where It works for .pfx file.

Loading Public Key Certificates
Azure Key Vault Explorer allows you to load public key certificates (.cer files).
Certificates are stored as keys in the Key Vault using a "standard" format used by that application (since .cer files aren't natively supported by Azure Key Vault).
Accessing Public Key Certificates
Once you have loaded public keys into the Azure Key Vault, they can then be accessed programatically as follows:
// load certificate based on format used by `Azure Key Vault Explorer`
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var certBundle = await kv.GetSecretAsync(secretIdentifier).ConfigureAwait(false);
byte[] certBytes = null;
if (certBundle.ContentType == "application/x-pkcs12")
{
certBytes = Convert.FromBase64String(certBundle.Value);
}
else if (certBundle.ContentType == "application/pkix-cert")
{
certBytes = certBundle?.Value.FromJson<PublicKeyCertificate>()?.Data;
}
if (certBytes != null && certBytes.Length > 0)
{
return new X509Certificate2(certBytes,
"",
X509KeyStorageFlags.Exportable |
X509KeyStorageFlags.MachineKeySet |
X509KeyStorageFlags.PersistKeySet);
}
return null;
...
// class used to access public key certificate stored in Key Vault
public class PublicKeyCertificate
{
public byte[] Data;
}

You should consider if Key Vault is the appropriate solution for your scenario. The public key (by nature) is not confidential data, you don't need a secure place to store it. You can use a general purpose storage service for it.
If you still need to use Key Vault, you can store it as a secret. Key Vault secrets are octet sequences with a maximum size of 25k bytes each.

Related

Create signature using Pkcs11Interop without token password

I'm using the Pkcs11Interop in combination with a certificate on a usb stick to sign pdf documents.
The following steps are executed to sign a document:
Load the pkcs11 library (LoadPkcs11Library)
Get a slot of the selected smartcard/usb token
OpenSession on the slot (Requires the slot pin)
Perform login on the session
Search the private key handle
sign the document (Requires the pin)
Corresponding code:
private byte[] GetSignatureFromHashViaPkcs11(byte[] hash, string pin)
{
Pkcs11InteropFactories factories = new Pkcs11InteropFactories();
using (IPkcs11Library pkcs11Library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, PKCS11LibPath, AppType.SingleThreaded))
{
ISlot slot = LoadSlot(pkcs11Library, CertificateToUse.BelongsToSmartCardSlot.TokenSerial);
using (ISession session = slot.OpenSession(SessionType.ReadOnly))
{
session.Login(CKU.CKU_USER, pin);
//Search the private key based on the pulblic key CKA_ID
IObjectHandle keyHandle = null;
var searchTemplate = new List<IObjectAttribute>()
{
//CKO_PRIVATE_KEY in order to get handle for the private key
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
//CKA_ID searching for the private key which matches the public key
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_ID, CertificateToUse.PublicKeyCKAID.GetValueAsByteArray()),
};
//filter the search result. Since we search for a private key, only one is returned for each certificate
var search = session.FindAllObjects(searchTemplate);
keyHandle = search.FirstOrDefault();
if (keyHandle == null || (keyHandle.ObjectId == CK.CK_INVALID_HANDLE))
{
throw new Exception("Unable to read SmartCard KeyHandle. Make sure the correct PKCS11 Library is used");
}
try
{
//Create the signature (using the pin)
var pinAsByteArray = UTF8Encoding.UTF8.GetBytes(pin);
using (IMechanism mechanism = session.Factories.MechanismFactory.Create(CKM.CKM_SHA256_RSA_PKCS))
return session.Sign(mechanism, keyHandle, pinAsByteArray, hash);
}
catch (Exception ex)
{
throw new Exception("Error creating the signature", ex);
}
}
}
}
This solution works if the slot pin and the private key pin are the same.
In case those pins are different the above code doesn't work since only one pin is used.
If i manage the slot pin and private key pin manually in code, everything works.
But it seems it should be possible to create a signature without having to perform an OpenSession before.
My customer has an old tool which does only require the private key pin in order to sign a document (Which means it is technically possible to sign without having the slot pin).
My problem is that i currently require to do the session.Login with the slot pin in order to get the private key handle.
Question: Is there another way of signing a document using Pkcs11Interop without having to first do a session.Login. Or is there another way of getting the private key handle without having to first do a session.Login?
If the customer is not willing to trust you with the slot pin perhaps you can build an intermediate adaptor service which in turn can perform the signing and publishes this capability as an api with some authentication that you can pass the payload into and it will sign and return it.
The client would then be free to manage the intermediate component and initialise it with slot pin.

How to generate or create private / public key in flutter?

I need to generate a keypair in my Flutter app, There is one library called RSA which does parse a pair of public/private keys and is able to encrypt and decrypt strings using them, but it doesn't have the ability to generate a new KeyPair (preferably from a given string).
How can I generate the keys in the first place? Am I missing something?
//Future to hold our KeyPair
Future<crypto.AsymmetricKeyPair> futureKeyPair;
//to store the KeyPair once we get data from our future
crypto.AsymmetricKeyPair keyPair;
Future<crypto.AsymmetricKeyPair<crypto.PublicKey, crypto.PrivateKey>> getKeyPair()
{
var helper = RsaKeyHelper();
return helper.computeRSAKeyPair(helper.getSecureRandom());
}
It's easy using the fast_rsa package:
import 'package:fast_rsa/fast_rsa.dart';
KeyPair keyPair1 = await RSA.generate(2048);
print(keyPair1.privateKey);
print(keyPair1.publicKey);
https://pub.dev/packages/fast_rsa

Azure Key Vault Quickstart fails to provide key vault client

I am learning the Azure Key Vault. I am trying to follow https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-net. I have created a vault in the portal, assigned an access policy for a user account. I have seen the vault in the protal, and I have seen that the user has I have set the environment variable value. I use an 'az login' command at a prompt to use that account. From the prompt I run the code in the quickstart. It prompts for a secret. I enter 'bob.' It throws an exception.
"Creating a secret in [...]-key-vault called 'mySecret' with the value 'bob' ...Unhandled exception. Azure.Identity.AuthenticationFailedException: SharedTokenCacheCredential authentication failed: A configuration issue is preventing authentication - check the error message from the server for details.You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS70002: The client does not exist or is not enabled for consumers. If you are the application developer, configure a new application through the App Registrations in the Azure Portal at https://go.microsoft.com/fwlink/?linkid=2083908."
The exception is at
await client.SetSecretAsync(secretName, secretValue);
I think the problem is coming from
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
The client is not able to send tokens that the vault accepts. I am at a loss. I have had a couple of people with some expertise in using the Vault review this code and they haven't been able to provide insight. Any help?
Here is the code, from the example:
using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace key_vault_console_app
{
class Program
{
static async Task Main(string[] args)
{
const string secretName = "mySecret";
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
var kvUri = $"https://{keyVaultName}.vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
Console.Write("Input the value of your secret > ");
var secretValue = Console.ReadLine();
Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
await client.SetSecretAsync(secretName, secretValue);
Console.WriteLine(" done.");
Console.WriteLine("Forgetting your secret.");
secretValue = string.Empty;
Console.WriteLine($"Your secret is '{secretValue}'.");
Console.WriteLine($"Retrieving your secret from {keyVaultName}.");
var secret = await client.GetSecretAsync(secretName);
Console.WriteLine($"Your secret is '{secret.Value}'.");
Console.Write($"Deleting your secret from {keyVaultName} ...");
DeleteSecretOperation operation = await client.StartDeleteSecretAsync(secretName);
// You only need to wait for completion if you want to purge or recover the secret.
await operation.WaitForCompletionAsync();
Console.WriteLine(" done.");
Console.Write($"Purging your secret from {keyVaultName} ...");
await client.PurgeDeletedSecretAsync(secretName);
Console.WriteLine(" done.");
}
}
}
Not Sure the root reason for it. But If you want to use a user account to login to Azure and access your key vault, using UsernamePasswordCredential() could be a workaround here.
To use UsernamePasswordCredential(), you should register a client application in Azure AD: Go to Azure portal =>Azure Active Directory => New registration
Note its application ID:
Go to API permissioms, and grant key vault user_impersonation permission so that users could access key vault via this app.
Click "Grant admin consent for.." to finish the permission grant process.
Go to the "Authentication" blade, turn on "Allow public client flows" so that Azure will consider this app as a public client:
Try the code below to create a secret:
using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
namespace key_vault_console_app
{
class Program
{
static async Task Main(string[] args)
{
const string secretName = "mySecret2";
var keyVaultName = "<your kv name>";
var kvUri = $"https://{keyVaultName}.vault.azure.net";
var userCred = new UsernamePasswordCredential("<user account name>", "<user password>", "<your tenant name/id>", "<client application ID WHCIH we created above>");
var client = new SecretClient(new Uri(kvUri), userCred);
Console.Write("Input the value of your secret > ");
var secretValue = Console.ReadLine();
Console.Write($"Creating a secret in {keyVaultName} called '{secretName}' with the value '{secretValue}' ...");
await client.SetSecretAsync(secretName, secretValue);
Console.WriteLine(" done.");
}
}
}
Result:

OAuth2 - How to add a list of clientId/ client secret as a JSON file instead of a single client id / client secret?

In order to secure the communications between my services, I created an Authorization server that generates an access token. my application is storing the Client ID and Client Secret and pass those to the Authorization server in exchange for an access token.
The client ID & my client secret are stored in my configure() method:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws
Exception {
clients.inMemory().withClient("xxx").secret("xxx")
.authorizedGrantTypes("client_credentials").scopes("resource-
server-read", "resource-server-write");
}
My question is how can I created multiple client ID & client secret in a JSON file instead of a single value?

Azure web app with access to multiple key vaults

I'm wondering if an Azure web application can have access to multiple key vaults? This is because one of our web applications has multiple database connection strings and each of the databases has columns encrypted with always encrypted and the column encryption keys will be stored in their own key vaults per database. If this is possible, how does the web application know which key vault to access to get the column encryption key for the respective database it's connecting to?
Currently the web application has access to one key vault and all of the databases are encrypted with the same column encryption key which is in this key vault. But I want to split this out so each database has it's own key vault and respective column encryption key for better security. The web application obtains access to the key vault via Azure Active Directory with the client id and secret mechanism. I've played around with adding the Azure Active Directory application to the multiple key vaults using the key vault access policy but not sure if this is correct/will work.
The code I'm using to wire up the column encryption key with the web application (which appears to be key vault agnostic):
public static void InitializeAzureKeyVaultProvider()
{
var clientId = ConfigurationManager.AppSettings["AuthClientId"];
var clientSecret = ConfigurationManager.AppSettings["AuthClientSecret"];
_clientCredential = new ClientCredential(clientId, clientSecret);
SqlColumnEncryptionAzureKeyVaultProvider azureKeyVaultProvider =
new SqlColumnEncryptionAzureKeyVaultProvider(GetToken);
Dictionary<string, SqlColumnEncryptionKeyStoreProvider> providers =
new Dictionary<string, SqlColumnEncryptionKeyStoreProvider>
{
{SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, azureKeyVaultProvider}
};
SqlConnection.RegisterColumnEncryptionKeyStoreProviders(providers);
}
private static async Task<string> GetToken(string authority, string resource, string scope)
{
var authContext = new AuthenticationContext(authority);
var result = await authContext.AcquireTokenAsync(resource, _clientCredential);
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the access token");
}
return result.AccessToken;
}
Thoughts?

Resources