Get the CERT_RDN information from the certificate object - ssl

I'm opening the certificate store using the "CertOpenStore" API and get the certificates using the "CertEnumCertificatesInStore" API.
The CERT_CONTEXT data returned by the API gives the issuer name in CERT_NAME_BLOB type.
How to get the CERT_RDN or CERT_NAME_INFO from the certificate.?
My requirement is to get the issuer name attributes (O, OU, etc.). I do not want to parse the string returned by the CertNameToStr API.

The above comment is correct, you do need to decode the ASN.1 encoded data in the CERT_NAME_BLOB. However, the CryptoAPI has a function to do this for you - CryptDecodeObject.
If you have a PCCERT_CONTEXT handle pCertContext, you can decode it to a CERT_NAME_INFO structure as follows:
BOOL success = CryptDecodeObject(
X509_ASN_ENCODING,
X509_NAME,
pCertContext->pCertInfo->Issuer.pbData,
pCertContext->pCertInfo->Issuer.cbData,
0,
NULL,
&dwNameInfoSize);
// (check that CryptDecodeObject succeeded)
PCERT_NAME_INFO pCertNameInfo = (PCERT_NAME_INFO) malloc(dwNameInfoSize);
// (check that malloc succeeded)
CryptDecodeObject(
X509_ASN_ENCODING,
X509_NAME,
pCertContext->pCertInfo->Issuer.pbData,
pCertContext->pCertInfo->Issuer.cbData,
0,
pCertNameInfo,
&dwNameInfoSize);
Now you can loop through the different components of the RDN like this:
for (DWORD i = 0; i < pCertNameInfo->cRDN; i++)
{
for (DWORD j = 0; j < pCertNameInfo->rgRDN[i].cRDNAttr; j++)
{
CERT_RDN_ATTR &rdnAttribute = pCertNameInfo->rgRDN[i].rgRDNAttr[j];
//
// Do stuff with the RDN attribute
//
}
}
With each iteration, rdnAttribute will be set to a different component of the issuer name like you want.
Finally, free the memory when you're done:
free(pCertNameInfo);

Related

Send certificate in http request header - c++

I have a certificate that I need to send in the header of an http request. This is how I acquired the cert:
PCCERT_CONTEXT cert = nullptr;
wstring store = // store name
wstring subjectName = // subject name
HCERTSTORE hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
store.c_str());
cert = CertFindCertificateInStore(
hStoreHandle,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
subjectName.c_str(),
NULL);
I need to send it as a custom header, as the load balancer that sits in front of my service strips off the certificate header ["X-ARR-CLIENTCERT"] before forwarding the request. I believe I need to send the cert->pbCertEncoded, but on the server, I can't decode it and convert it back to an X509Certificate2.
This is what I tried on the client:
request.headers().add("client-cert", cert->pbCertEncoded);
On the server:
var headerCert = Request.Headers["client-cert"];
byte[] certdata = Convert.FromBase64String(headerCert);
X509Certificate2 cert = new X509Certificate2(certdata);
The request header on the server is non-null. But it cannot parse it back to an X509Certificate2.
I tried another thing on the client. After getting the cert, I converted it to a string
DWORD size = 0;
CryptBinaryToString(cert->pbCertEncoded, cert->cbCertEncoded, CRYPT_STRING_BASE64, NULL, &size);
LPWSTR outstring = new TCHAR[size];
CryptBinaryToString(cert->pbCertEncoded, cert->cbCertEncoded, CRYPT_STRING_BASE64, outstring, &size);
If I try to send outstring in the header, it complains:
WinHttpAddRequestHeaders: 87: The parameter is incorrect.
But when I take the contents of outstring and try to parse it on the server, it decodes back to the right certificate. This tells me that I'm not doing something right when passing cert->pbCertEncoded in the header. Maybe I need to re-encode it or transform it somehow so the server can correctly parse it? I'd appreciate any help. Thanks!
My client is in c++ and server in .NET. I'm using cpprestsdk to send the certificate in the http request.
The pbCertEncoded is the ASN.1 encoded representation of the certificate. Look for instance here.
So you must encode the bytes to base64 for instance like this:
#include <Wincrypt.h>
#pragma comment (lib, "Crypt32.lib")
int ToBase64Crypto(const BYTE* pSrc, int nLenSrc, char* pDst, int nLenDst )
{
DWORD nLenOut = nLenDst;
BOOL fRet = CryptBinaryToString(
(const BYTE*)pSrc,
nLenSrc,
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
pDst, &nLenOut
);
if (!fRet) {
nLenOut=0; // failed
}
return (nLenOut);
}

How I can mark a eMail with Userlabel (not the complete Thread)

I have created this script:
function myFunctionNew() {
var threads = GmailApp.search('in:inbox subject:"xxxxxxxxxxxxxx" ');
GmailApp.markThreadsUnread(threads);
for (var i = 0; i < threads.length; i++) {
var mid = threads[i].getId();
GmailApp.getMessageById(mid).markRead();
GmailApp.getMessageById(mid).star();
// ---> so I mark the complete Thread: GmailApp.getUserLabelByName("1").addToThread(threads[i]);
// Here I want to sign only the one eMail with a User label (e.g. Customer)
//
// ---> GmailApp.moveThreadToArchive(threads[i]);
// Here I want to move only the one eMail to the archive
GmailApp.getMessageById(id).forward("xxxxxxxxxx#yyyyyy.com");
}
}
but how I can add a label and move only one eMail which ID I have?
Thanks
Your request can be accomplished with the Gmail API
The Gmail API offers you more options than GmailApp, among others labelling individual messages instead of the whole thread
The Gmail API can be used in Apps Script as Advanced Gmail Service
All you need to do for it is to enable the service by going on Resources > Advanced Google services.... in your Apps Script editor
The specific method you need to add a user label to a single message is Gmail.Users.Messages.modify(resource, userId, id) with the resource {"addLabelIds": [labelId]}
It is important to use for your requests that concern only one message instead of the whole thread the message id, which is different from the thread id.
If you do not know your message id, you need to specify how to find it (e.g. specify the snipept of interest as a search criteria).
It is also important to know that you need to specify the labelId instead of labelName, which for user labels opposed from standard labels are distinct.
If you do not know the label id, you need to loop through all labels by their name until you find the correct one
Below is a sample code showing how to add a label and perform other operations on single messages with a combination of GmailApp and Gmail API
function myFunctionNew() {
var labels = Gmail.Users.Labels.list("me").labels;
for (var a = 0; a < labels.length; a++) {
if(labels[a].name == "Customer"){
var labelId = labels[a].id;
break;
}
}
var threads = GmailApp.search('in:Inbox subject:"xxxxxxxxxxxxxx" ');
for (var i = 0; i < threads.length; i++) {
var mid = threads[i].getId();
//retrieve the thread with Gmail API to obtain the ids of the thread messages correctly
var thread = Gmail.Users.Threads.get("me", mid);
// retrieve all messages and their id for each thread
var messages = thread.messages;
for (var j = 0; j < messages.length; j++) {
var message = messages[j];
//retrieve the message id
var messageId = message.id;
//perform the desired actions with the message id
GmailApp.getMessageById(messageId).markRead();
GmailApp.getMessageById(messageId).star();
//now, you need to chose which messages you want to label, for example selectt by snippet:
var snippet = message.snippet;
if (snippet == "Paste here the snippet"){
var myId = messageId;
//only the messages with the specified snippet will be labelled and forwarded instead of the whole thread:
Gmail.Users.Messages.modify({"addLabelIds": [labelId]}, "me", myId);
GmailApp.getMessageById(myId).forward("xxxxxxxxxx#yyyyyy.com");
}
}
}
}

Signing ECDSA with private key with curve secp224k1

I want to get sign by ECDSA secp224k1. I cannot get the same signature as in the CoinFLEX Authentication Process example from the manual. I am using C# BouncyCastle.
Why can't I get manual page's signature ​​by my code?
// manual page's step 7
byte[] fortyByteMessage = fromHexStringToByteArr("0x00000000 00000001").Concat(fromHexStringToByteArr("0x6b347302 2e6b9b5a f2fe5d1d ae7cf5bf")).Concat(fromHexStringToByteArr("0xf08c98ca f1fd82e8 cea9825d bff04fd0")).ToArray();
// manual page's step 9
byte[] privateKey = fromHexStringToByteArr("0xb89ea7fc d22cc059 c2673dc2 4ff40b97 83074646 86560d0a d7561b83");
// manual page's step 10
X9ECParameters spec = ECNamedCurveTable.GetByName("secp224k1");
ECDomainParameters domain = new ECDomainParameters(spec.Curve, spec.G, spec.N);
ECDsaSigner signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha224Digest()));
signer.Init(true, new ECPrivateKeyParameters(new BigInteger(privateKey), domain));
BigInteger[] signature = signer.GenerateSignature(fortyByteMessage);
byte[] r = signature[0].ToByteArray().SkipWhile(b => b == 0x00).Reverse().ToArray(); // (r) r should be 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e, but not.
Console.WriteLine(BitConverter.ToString(r).Replace("-", string.Empty).ToLower());
Expected byteArr ( step 10 r value ):
r = 0x3fb77a9d 7b5b2a68 209e76f6 872078c5 791340d5 989854ad a3ab735e<br>
My byteArr (this is wrong value, because it is different from step 10 r value )
r = 0x1e3b3f4f 7401ff9d 827b7222 47823919 452d3adb effa7aa4 52a0879e<br>
Another function:
static byte[] fromHexStringToByteArr(string paramHexString)
{
string hexString = paramHexString.Substring(2).Replace(" ", "");
byte[] result = new byte[hexString.Length / 2];
int cur = 0;
for (int i = 0; i < hexString.Length; i = i + 2)
{
string w = hexString.Substring(i, 2);
result[cur] = Convert.ToByte(w, 16);
cur++;
}
return result;
}
According to step 10 of the instructions, not the 40-byte-message should be signed, but the SHA224-hash of this message: The client signs the 28-byte SHA-224 digest of the 40-byte message.... Note, that the data are not automatically hashed by the GenerateSignature-method, i.e. it must be hashed explicitly, see also here and these examples.
The Org.BouncyCastle.Math.BigInteger.ToByteArray-method (which is used in the C#-code) outputs the byte-array in big-endian-format (unlike .Net, whose System.Numerics.BigInteger.ToByteArray-method uses the little-endian-format). Therefore, it is not necessary to reverse the byte-order (using the Reverse-method).
With these modifications, the signature is:
r = 0x1781ff4997b48d389f518df75001c4b6564082956228d74dd0321656
s = 0x0aadc68cf78dc75d44fb300f200465e72a70826ec2d5577d49b62e59
which, however, still differs from the signature shown in the instructions.
In the C#-code, the ECDsaSigner-instance is created with a HMacDsaKCalculator-instance, generating a deterministic signature based on RFC6979. When creating a signature with ECDSA, the k-parameter is chosen randomly for the non-deterministic ECDSA, whereas in the deterministic variant it is created from the message and the private key according to a specific algorithm (described in RFC6979), see here. Thus, the deterministic variant generates the same signature for the same message and private key, while the non-deterministic variant generates different signatures.
Probably the difference between the signatures is caused by the use of the non-deterministic variant by CoinFLEX. Unfortunately, the instructions do not go into detail about the ECDSA-procedure used.
Update:
Both variants, deterministic and non-deterministic, provide valid ECDSA-signatures! Before the deterministic variant (RFC6979 is from August 2013) there was only the non-deterministic variant, see here.
I installed and tested the sign_secp224k1-tool on a Linux (Debian) machine. As suspected, the tool generates different signatures for the same private key and the same message, obviously using the non-deterministic variant. This can also be easily verified from the source-code: The signature is calculated using the ecp_sign-method, which randomly determines the k-value using /dev/urandom.
Thus it is clear that the signature generated by the C#-code using the deterministic variant generally cannot match a signature generated by the sign_secp224k1-tool using the non-deterministic variant.

Creating a private/public key with 64 characters that are already known using bitcoinjs

So I'm trying to create a private/public key from 64 characters that I already know using bitcoinjs with the code below:
key = Bitcoin.ECKey.makeRandom();
// Print your private key (in WIF format)
document.write(key.toWIF());
// => Kxr9tQED9H44gCmp6HAdmemAzU3n84H3dGkuWTKvE23JgHMW8gct
// Print your public key (toString defaults to a Bitcoin address)
document.write(key.pub.getAddress().toString());
// => 14bZ7YWde4KdRb5YN7GYkToz3EHVCvRxkF
If I try to set "key" to my 64 characters instead of "Bitcoin.ECKey.makeRandom();" it fails. Is there a method or library that I overlooked that would allow me to use the known 64 characters in order to generate the private key in wif format and the public address?
Thanks in advance to anyone that may be able to offer some help.
You should use fromWIF method to pass your own data.
from source code of eckey.js
// Static constructors
ECKey.fromWIF = function(string) {
var payload = base58check.decode(string)
var compressed = false
// Ignore the version byte
payload = payload.slice(1)
if (payload.length === 33) {
assert.strictEqual(payload[32], 0x01, 'Invalid compression flag')
// Truncate the compression flag
payload = payload.slice(0, -1)
compressed = true
}
To create WIF from your key please follow https://en.bitcoin.it/wiki/Wallet_import_format
Here is interactive tool http://gobittest.appspot.com/PrivateKey
The solution to generate private and public key:
//public-key
var address = eckey.getBitcoinAddress().toString();
var privateKeyBytesCompressed = privateKeyBytes.slice(0);
privateKeyBytesCompressed.push(0x01);
var privateKeyWIFCompressed = new Bitcoin.Address(privateKeyBytesCompressed);
privateKeyWIFCompressed.version = 0x80;
//private-key
privateKeyWIFCompressed = privateKeyWIFCompressed.toString();
Take a look at moneyart.info for beautifully designed paperwallets.

the signature includes en embedded timeStamp but it could not be verified

I've just added timestamp to my pdf. signature is valid. timestamp token is correct too (I checked already). but adobe reader tells me that "signature includes an embedded timestamp but it could not be veridied".
AttributeTable unsigned = signerInformation.getUnsignedAttributes();
Hashtable<ASN1ObjectIdentifier, Attribute> unsignedAttrHash = null;
if (unsigned == null) {
unsignedAttrHash = new Hashtable<ASN1ObjectIdentifier, Attribute>();
} else {
unsignedAttrHash = signerInformation.getUnsignedAttributes().toHashtable();
}
unsignedAttrHash.put(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken, signatureTimeStamp);
SignerInformation newSignertInformation = SignerInformation.replaceUnsignedAttributes(si, new AttributeTable(unsignedAttrHash));
I fount this code at stackowerflow. it works. it's really correct code. finally I have new SignerInformationStore and new CMS Signed Data like this
CMSSignedData.replaceSigners(oldCMSSignedData, newSignerStore);
but maybe something is missing in my PDF? certificate or something like that?
that's sample pdf
The message imprint in the signature-time-stamp seems to be not correct. It is expected to have the SHA256 of the signature value in this message imprint.
SHA256 of the signature value:
1b4532052d612ca32ae96b9a8e7aa6d64ae6c69dc00e1b7b31394ac3b54c4049
The message imprint in the time-stamp token:
E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855