Use Custom CNG provider to get Private key from the HSM - cryptography

I have our own CNG provider. Using c# with .net framework 4.6.1 with window 7. I am using clrsecurity.
string fp = "223298a5c7c9f78a42d83a5ffbxxxxxxxx";
//string fp = "331ffa497d90d19446171f85xxxxxxxx"; //MS
// Load the certificate with the specified serial number
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindBySerialNumber, fp, false);
// check if at least one certificate has been found
if (certificates.Count != 1)
{
throw new Exception("The certificate with the serial number " + fp + " could not be found.");
}
X509Certificate2 cert = certificates[0];
CngKey cngKey = null;
if (cert.HasCngKey())
{
//rsa = cert.GetRSAPrivateKey();
cngKey = cert.GetCngPrivateKey();
}
Property of cngKey:
The problem is I am not able to set the provider name into CngKey object.
So how to use the clrsecurity dll for non Microsoft KSP.

Related

Which certificates are required for iText.Signatures.OcspClientBouncyCastle GetEncoded

I want to set the ocsp when signing pdf document using iText
The ocsp is created using the following code:
OCSPVerifier ocspVerifier = new OCSPVerifier(null, null); // can be null based on https://stackoverflow.com/questions/40765907/itextsharp-ocspclientbouncycastle-constructor-is-deprecated-whats-the-replacem
IOcspClient ocspClient = new OcspClientBouncyCastle(ocspVerifier);
var test = ocspClient.GetEncoded(rootCertificate, cert, "http://my-url.com");
The result of this code is null.
I guess it's because i set the wrong certificates.
The first parameter is named checkCert and the second one issuerCert
Note: I'm using iText version 7.1. It seems the names were changed to checkCert/rootCert in version 7.7
What exactly are checkCert and issuerCert?
I tried with the signing root certificate as checkCert and the signature certificate as issuerCert but it doesn't work.
Any idea or explanation which certificates are required here?
Edit:
The following is the code which i use to create the pkcs7 container which should include the ocsp:
OCSPVerifier ocspVerifier = new OCSPVerifier(null, null); // null,null >https://stackoverflow.com/questions/40765907/itextsharp-ocspclientbouncycastle-constructor-is-deprecated-whats-the-replacem
IOcspClient ocspClient = new OcspClientBouncyCastle(ocspVerifier);
var ocsp = ocspClient.GetEncoded(cert, rootCertificate, "http://www.my.com/aia/ocsp");
if (ocsp == null)
Console.WriteLine("oscp is null");
else
Console.WriteLine("ocsp is not null");
//Create the pkcs7 container
PdfPKCS7 sgn = new PdfPKCS7(null, c.ToArray(), HashAlgorithm, false);
byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, ocsp, null, PdfSigner.CryptoStandard.CMS);
//Load the signature via pkcs11 hardware
byte[] extSignature = GetSignatureFromHashViaPkcs11(sh, pin);
sgn.SetExternalDigest(extSignature, null, DigestEncryptionAlgorithm);
var ret = sgn.GetEncodedPKCS7(hash, tsaClient, ocsp, null, PdfSigner.CryptoStandard.CMS);
No matter how i set the certificates in ocspClient.GetEncoded, the resulting ocsp is always null
Even a more fundamental question: Are the issuer and root certificate the certificates i use for creating the signature or are those the certificates from the ocsp?

How to verify PKCS#7 signature in PHP

I have a digital signature (encrypted format PKCS#7) needs to be verified So I have tried by using different PHP core methods(openssl_verify, openssl_pkcs7_verify and even tried by external library such as phpseclib But nothing worked :(
I get a signature along with some extra params through by this link..
http://URL?sign={'param':{'Id':'XXXXXXX','lang':'EN','Rc':'00','Email': 'test#yahoo.com'’},'signature':'DFERVgYJKoZIhvcNAQcCoIIFRzCCBUMCAQExCzAJBgUrDg
MCGgUAMIGCBgkqhkiG9w0BBwGgdQRzeyJEYXRlIjoidG9fY2hhcihzeXNkYXRlJ0RETU1ZWVlZJykgIiwiSWQiOiJ
VMDExODg3NyIsIklkaW9tYSI6IkNBUyIsIk51bUVtcCI6IlUwM23D4DEE3dSi...'}
PHP code - returns always 0(false) instead of 1(true).
$JSONDATA = str_replace("'", '"', #$_GET["sign"]);
$data = json_decode($JSONDATA, true);
$this->email = $data['param']["EMAIL"];
$this->signature = $data['signature'];
$this->signature_base64 = base64_decode($this->signature);
$this->dataencoded = json_encode($data['param']);
//SOLUTION 1 (By using phpseclib) but didnt work..
$rsa = $this->phpseclib->load();
$keysize = 2048;
$rsa->setPrivateKeyFormat(CRYPT_RSA_PRIVATE_FORMAT_PKCS8);
$rsa->setPublicKeyFormat(CRYPT_RSA_PUBLIC_FORMAT_PKCS1);
$d = $rsa->createKey($keysize);
$Kver = $d['publickey'];
$KSign = $d['privatekey'];
// Signing
$rsa->loadKey($KSign);
$rsa->setSignatureMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->setHash('sha256');
$signature = $rsa->sign($this->dataencoded);
$signedHS = base64_encode($signature);
// Verification
$rsa->loadKey($Kver);
$status = $rsa->verify($this->dataencoded, $this->firma_base64); // getting an error on this line Message: Invalid signature
var_dump($status); // reutrn false
//SOLUTION 2 (By using code php methods)
// obtener la clave pública desde el certifiado y prepararla
$orignal_parse = parse_url("https://example.com", PHP_URL_HOST);
$get = stream_context_create(array("ssl" => array("capture_peer_cert" => TRUE)));
$read = stream_socket_client("ssl://".$orignal_parse.":443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
$cert = stream_context_get_params($read);
$certinfo = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
openssl_x509_export($cert["options"]["ssl"]["peer_certificate"],$cert_key);
$pubkeyid = openssl_pkey_get_public($cert_key);
$dataencoded = json_encode($data['param']);
echo $ok = openssl_x509_check_private_key($cert_key,$this->firma_base64); // return nothing
echo $ok1 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA256); // returns 0
echo $ok2 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA512); // returns 0
echo $ok3 = openssl_verify($dataencoded, $this->firma_base64, $pubkeyid, OPENSSL_ALGO_SHA256); // returns 0
echo $ok4 = openssl_verify($dataencoded, $this->firma, $pubkeyid, OPENSSL_ALGO_SHA512); // returns 0
Java code - (this code works and returns true)
private boolean verifySignautre(String frm) throws NetinfException, IOException, CMSException,
CertificateException, OperatorCreationException, Exception {
Security.addProvider(new BouncyCastleProvider());
//we extract the containers that make up the signature and the keystore used to sign included in the same signature.
CMSSignedData signedData = new CMSSignedData(Base64.decode(frm.getBytes()));
SignerInformationStore signers = signedData.getSignerInfos();
Store certStore = signedData.getCertificates();
Collection c = signers.getSigners();
Iterator it = c.iterator();
while (it.hasNext()) {
//retrieve the certificate with the recipient's id.
SignerInformation signerInfo = (SignerInformation) it.next();
Collection certCollection = certStore.getMatches(signerInfo.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder signerCertificateHolder = (X509CertificateHolder) certIt.next();
//create the container to validate signature.
ContentVerifierProvider contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(new
DefaultDigestAlgorithmIdentifierFinder()).build(signerCertificateHolder);
//valid signature and then certificate validity date
try{
X509Certificate signedcert = new
JcaX509CertificateConverter().setProvider("BC").getCertificate(signerCertificateHolder);
signedcert.checkValidity();
signedcert.verify(signedcert.getPublicKey());
return true;
}catch(Exception e){
return false;
}
}
I simply need to convert this Java code into PHP. However, as you can see above that I tried different approaches but none of them worked.
Please support me to find the solution.
your support would be higly appreciated

Azure Pack REST API Authentication

After hours of search in Microsoft messed up API documentation for its products, i am still no where on how to authenticate a rest API request in windows azure pack distribution.
Primarily i want to create an API which automate the process of deploying virtual machine, but I cant find any documentation on how to acquire the authentication token to access the resources.
Some documentation states the use of ADFS, but don't provide any reference on the ADFS REST API for authentication.
And I don't want to use ADFS in the first place. I want to authenticate using AZURE tenant and admin interface.
In conclusion, if anyone can provide any help on the REST API authentication, it will make my day.
Thanks in advance.
You can use the following PowerShell to acquire an access token.
Add-Type -Path 'C:\Program Files\Microsoft Azure Active Directory Connect\Microsoft.IdentityModel.Clients.ActiveDirectory.dll'
$tenantID = "<the tenant id of you subscription>"
$authString = "https://login.windows.net/$tenantID"
# It must be an MFA-disabled admin.
$username = "<the username>"
$password = "<the password>"
# The resource can be https://graph.windows.net/ if you are using graph api.
# Or, https://management.azure.com/ if you are using ARM.
$resource = "https://management.core.windows.net/"
# This is the common client id.
$client_id = "1950a258-227b-4e31-a9cf-717495945fc2"
$creds = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" `
-ArgumentList $username,$password
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" `
-ArgumentList $authString
$authenticationResult = $authContext.AcquireToken($resource,$client_id,$creds)
# An Authorization header can be formed like this.
$authHeader = $authenticationResult.AccessTokenType + " " + $authenticationResult.AccessToken
I am doing some similar job like you did.
static string GetAspAuthToken(string authSiteEndPoint, string userName, string password)
{
var identityProviderEndpoint = new EndpointAddress(new Uri(authSiteEndPoint + "/wstrust/issue/usernamemixed"));
var identityProviderBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential);
identityProviderBinding.Security.Message.EstablishSecurityContext = false;
identityProviderBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
identityProviderBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
var trustChannelFactory = new WSTrustChannelFactory(identityProviderBinding, identityProviderEndpoint)
{
TrustVersion = TrustVersion.WSTrust13,
};
//This line is only if we're using self-signed certs in the installation
trustChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication() { CertificateValidationMode = X509CertificateValidationMode.None };
trustChannelFactory.Credentials.SupportInteractive = false;
trustChannelFactory.Credentials.UserName.UserName = userName;
trustChannelFactory.Credentials.UserName.Password = password;
var channel = trustChannelFactory.CreateChannel();
var rst = new RequestSecurityToken(RequestTypes.Issue)
{
AppliesTo = new EndpointReference("http://azureservices/TenantSite"),
TokenType = "urn:ietf:params:oauth:token-type:jwt",
KeyType = KeyTypes.Bearer,
};
RequestSecurityTokenResponse rstr = null;
SecurityToken token = null;
token = channel.Issue(rst, out rstr);
var tokenString = (token as GenericXmlSecurityToken).TokenXml.InnerText;
var jwtString = Encoding.UTF8.GetString(Convert.FromBase64String(tokenString));
return jwtString;
}
Parameter "authSiteEndPoint" is your Tenant Authentication site url.
default port is 30071.
You can find some resource here:
https://msdn.microsoft.com/en-us/library/dn479258.aspx
The sample program "SampleAuthApplication" can solve your question.

C# "The request was aborted: Could not create SSL/TLS secure channel." - happening occasionally

This is a request to GoCardless test API from a Dynamics CRM plugin. I receive "The request was aborted: Could not create SSL/TLS secure channel." error. It only happens on the first request after some time without sending one. If I send it again, it will be OK. I would appreciate a lot your help.
Here is my code:
//I have tried all the following lines in comment without success
//ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
//ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
//ServicePointManager.Expect100Continue = true;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
// Create a new WebClient instance.
string baseURL = "https://api-sandbox.gocardless.com/";
WebClient client = new WebClient();
client.Headers.Add("Content-Type", "application/json");
client.Headers.Add("Authorization", "Bearer " + t);
client.Headers.Add("GoCardless-Version", "2015-07-06");
client.Headers.Add("Accept", "application/json");
Customers model = new Customers();
customer.country_code = "GB";
model.customers = customer;
MemoryStream stream1 = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Customers));
ser.WriteObject(stream1, model);
stream1.Position = 0;
StreamReader sr = new StreamReader(stream1);
// Apply ASCII Encoding to obtain the string as a byte array.
byte[] byteArray = Encoding.ASCII.GetBytes(sr.ReadToEnd());
ReturnedCustomers result = new ReturnedCustomers();
//Upload the input string using the HTTP 1.0 POST method.
try
{
byte[] responseArray = client.UploadData(baseURL + "customers", "POST", byteArray);
string responseText = Encoding.ASCII.GetString(responseArray);
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ReturnedCustomers));
using (Stream s = GenerateStreamFromString(responseText))
{
result = (ReturnedCustomers)serializer.ReadObject(s);
}
}
catch (WebException exception)
{
}
From the Microsoft documentation (https://msdn.microsoft.com/en-us/library/gg334752.aspx) are the following limitations:
Only the HTTP and HTTPS protocols are allowed.
Access to localhost (loopback) is not permitted.
IP addresses cannot be used. You must use a named web address that requires DNS name resolution.
Anonymous authentication is supported and recommended.
5.There is no provision for prompting the logged on user for credentials or saving those credentials.
The error may be due to seguneti things:
The certificate is invalid
The certification authority is not public
Could you check what is the value of ServicePointManager.Expect100Continue and ServicePointManager.SecurityProtocol attributes in your environment?

Why isn't Opc.Ua.UserIdentity sending the password cleanly to the OPC server?

I have a problem with the UserIdentity(user, password) constructor.
My password is 4 characters long. When the password arrives at the server it is 36 characters long. The first 4 characters are my password - the rest is random garbage.
The Opc.Ua.Client.dll & Opc.Ua.Core.dll have version 1.0.238.1.
What is causing this and what can I do to send the password correctly?
UPDATE
ApplicationConfiguration configuration = Helpers.CreateClientConfiguration();
X509Certificate2 clientCertificate = configuration.SecurityConfiguration.ApplicationCertificate.Find();
configuration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_CertificateValidation);
EndpointDescription endpointDescription = Helpers.CreateEndpointDescription(Url);
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(configuration);
endpointConfiguration.OperationTimeout = 300000;
endpointConfiguration.UseBinaryEncoding = true;
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
BindingFactory bindingFactory = BindingFactory.Create(configuration);
if (endpoint.UpdateBeforeConnect)
{
endpoint.UpdateFromServer(bindingFactory);
endpointDescription = endpoint.Description;
endpointConfiguration = endpoint.Configuration;
}
SessionChannel channel = SessionChannel.Create(
configuration,
endpointDescription,
endpointConfiguration,
bindingFactory,
clientCertificate,
null);
m_Session = new Session(channel, configuration, endpoint);
m_Session.ReturnDiagnostics = DiagnosticsMasks.All;
m_Session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
m_Session.Notification += new NotificationEventHandler(m_Session_Notification);
UserIdentity identity;
if (userName == null || userName.Length == 0)
{
identity = new UserIdentity();
}
else
{
identity = new UserIdentity(userName, password);
}
m_Session.Open("ATF UA client", identity);
log.Debug("Connect ok");
The rest is not garbage at all. It shall be the same ServerNonce you sent to the OPC UA Client in the CreateSessionResponse.
According to OPC UA specification the UserIdentityToken encrypted format is :
Length - Byte[4] => The length of your password
TokenData - Byte[*] => Your password
ServerNonce - Byte[*]
The password is 36 bytes long because OPC UA Server mainly use 32bytes ServerNonce and your password is 4 bytes long...
You should also verify that the ServerNonce sent with that UserIdentityToken is the same as the one you provide in your CreateSessionResponse.