Install self-signed certificate to personal store from .cer file using c++ - certificate

I try to create a certificate for testing purposes in two steps. First, I create a self-signed certificate which establishes my own Certification Authority (CA). Second, I use that root certificate to sign a test server certificate which will be placed in personal certificate store. I open an administrative command prompt and enter the following:
Step 1:
MakeCert -pe -n "CN=TestCA" -b 01/01/2015 -e 01/01/2020 -ss my -sr currentuser -a sha256 -sky signature -len 2048 -r "TestCA.cer"
Step 2:
MakeCert -pe -n "CN=localhost" -b 01/01/2015 -e 01/01/2020 -eku 1.3.6.1.5.5.7.3.1 -in "TestCA" -is my -ir currentuser -ss my -sr currentuser -a sha256 -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 -len 2048 "Localhost.cer"
Following those steps, everything works fine. After that, I try to install those certificates via c++ application. It seems to be fine when I check those certificates in certmgr.msc, however, client always fail to connect to server since then. After deleting certificate "localhost" from personal certificate store, then do step 2 using MakeCert.exe again. Client can success to connect to server. Maybe there is something important that I was missing. If anyone knows it, please give me some suggestions. By the way, my client and server are running in the same computer. My codes are shown below.
HCERTSTORE hMyCertStore = NULL;
if(hMyCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM, // The store provider type
0, // The encoding type is
// not needed
NULL, // Use the default HCRYPTPROV
CERT_SYSTEM_STORE_CURRENT_USER, // Set the store location in a
// registry location
L"MY" // The store name as a Unicode
// string
))
{
printf("The system store was created successfully.\n");
}
else
{
printf("An error occurred during creation "
"of the system store!\n");
exit(1);
}
CRYPTUI_WIZ_IMPORT_SRC_INFO importSrc;
memset(&importSrc, 0, sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO));
importSrc.dwSize = sizeof(CRYPTUI_WIZ_IMPORT_SRC_INFO);
importSrc.dwSubjectChoice = CRYPTUI_WIZ_IMPORT_SUBJECT_FILE;
importSrc.pwszFileName = L"C:\\Temp\\MakeCert\\localhost.cer";
importSrc.pwszPassword = L"";
importSrc.dwFlags = CRYPT_EXPORTABLE | CRYPT_USER_PROTECTED;
if (CryptUIWizImport(CRYPTUI_WIZ_NO_UI,
NULL,
NULL,
&importSrc,
hMyCertStore) == 0)
{
printf("CryptUIWizImport error %d\n", GetLastError());
}
Any help would be greatly appreciated.
Clement

I've found the difference between MakeCert and my application. After installing by MakeCert, I opened certificate dialog's General tab, then I found there is a string "You have a private key that corresponds to this certificate, but using my application, there is no string in the dialog. I think that I've missed some steps during the install procedure. If anyone know, please give me some suggestion.
Thanks.
Clement

Related

Is there a way to generate self signed certificates (X509 v3 with Subject Alternative Name) with my own root certificate to replace MakeCert.exe

I am having issues with makecert not able to generate a self-signed SSL certificate with Subject Alternative Name (SAN) in place. Latest versions of Google Chrome gives a security error when the website is accessed over HTTPS. I have read through several articles to try and understand the context and have come to the conclusion that makecert is old enough and won't be able to support X509 v3 certificate generation with SAN. Is there an alternative means for generating a self signed root certificate and intermediate certificates based on that root CA using something else that can run in Windows 7 and above please?
Root certificate is generated as follows:
makecert.exe -pe -ss Root -sr LocalMachine -n "CN=DIGITALMARKETRESEARCHAPPS PTY LTD, O=DIGITALMARKETRESEARCHAPPS PTY LTD, OU=DIGITALMARKETRESEARCHAPPS PTY LTD" -eku 1.3.6.1.5.5.7.3.1 -r -cy authority -a sha256
Intermediate certificate with the above Root CA is created as follows:
makecert.exe -pe -ss my -n "CN=www.myawesomesite.com.au, O=DIGITALMARKETRESEARCHAPPS PTY LTD, OU=DIGITALMARKETRESEARCHAPPS PTY LTD" -sky exchange -in "DIGITALMARKETRESEARCHAPPS PTY LTD"
I cannot seem to find a way to use either New-SelfsignedCertificateEx or New-SelfSignedCertificate to map exactly to the parameter above and create a certificate with the given root CA.
I will be really thankful for any help in the correct direction please.
At the moment, there is this old application that our clients use which makes use of makecert.exe to generate SSL certificates on the fly. Unfortunately this was done a long time ago and is hard to go back and tell them to change the whole architecture at this point. Google Xhrome in particular has been complaining about these certificates generated by makecert as explained in this article below:
http://news.thewindowsclub.com/deprecation-coming-to-google-chrome-heres-how-it-could-affect-your-workflow-88723/
http://www.telerik.com/blogs/understanding-fiddler-certificate-generators
The upcoming release of .NET Core 2.0 has added new classes to help here. While I know that either "powershell can" or "there's a version of powershell that does" work with .NET Core I don't know how, so there may be an adapter required for this answer.
Given signingCert, an X509Certificate2 instance which HasPrivateKey==true:
private static X509Certificate2 CreateNewCertificate(
X509Certificate2 signingCert,
int newRsaKeySize,
IEnumerable<string> sanDnsEntries)
{
var sanBuilder = new SubjectAlternativeNameBuilder();
string primaryDnsName = null;
foreach (string dnsEntry in sanDnsEntries)
{
// Let's just use the first one as the subject.
primaryDnsName = primaryDnsName ?? dnsEntry;
sanBuilder.AddDnsName(dnsEntry);
}
// New .NET Core Create(int) method. Or use
// rsa = RSA.Create(), rsa.KeySize = newRsaKeySize,
// or (on .NET Framework) new RSACng(newRsaKeySize)
using (RSA rsa = RSA.Create(newRsaKeySize))
{
var certRequest = new CertificateRequest(
$"CN={primaryDnsName}, O=Et OU=Cetera",
rsa,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
// Explicitly not a CA.
certRequest.CertificateExtensions.Add(
new X509BasicConstraintsExtension(false, false, 0, false));
certRequest.CertificateExtensions.Add(
new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.KeyEncipherment,
true));
// TLS Server EKU
certRequest.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection
{
new Oid("1.3.6.1.5.5.7.3.1"),
},
false));
// Add the SubjectAlternativeName extension
certRequest.CertificateExtensions.Add(sanBuilder.Build());
// Serial number.
// It needs to be unique per issuer.
// CA/Browser forum rules say 64 or more bits must come from a CSPRNG.
// RFC 3280 says not to use more than 20 bytes.
// Let's use 16 (two C# `long`s)
byte[] serialNumber = new byte[16];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(serialNumber);
}
// If you care about monotonicity (and believe your clock is monotonic enough):
{
long ticks = DateTime.UtcNow.Ticks;
byte[] tickBytes = BitConverter.GetBytes(ticks);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(tickBytes);
}
Buffer.BlockCopy(tickBytes, 0, serialNumber, 0, tickBytes.Length);
}
DateTimeOffset now = DateTimeOffset.UtcNow;
return certRequest.Create(
signingCert,
now,
now.AddDays(90),
serialNumber);
}
}
API Documentation

Package Family Name changed with new code signing cert

Previously we have one code signing cert, every thing working fine. Recently cert expired so we taken new cert from Comodo and released new build with that cert.
So here is the problem: Package Family Name Changed with that new cert, so I am not able to upgrade old installed apps with this new build packaged with new cert.
Need solution for this to maintain Package Family Name as constant or for new cert's also we need to provide upgrade for older apps.
How can we achieve this?
Error msg while upgrading package from PowerShell:
Add-AppxPackage : Deployment failed with HRESULT: 0x80073CF3, Package failed
updates, dependency or conflict validation.
Windows cannot install package df70dbc9-455c-4c32-b052-7ac2943630b7_1.0.193.1_x64__qbsrcgy0j364g
because a different package df70dbc9-455c-4c32-b052-7ac2943630b7_1.0.0.191_x64__hs446qhh7vdt4
with the same name is already installed. Remove package
df70dbc9-455c-4c32-b052-7ac2943630b7_1.0.0.191_x64__hs446qhh7vdt4 before
installing.
NOTE: For additional information, look for [ActivityId]
b0deec37-ac10-0001-81fd-deb010acd101 in the Event Log or use the command line
Get-AppxLog -ActivityID b0deec37-ac10-0001-81fd-deb010acd101
At C:\Users\\Desktop\\myappName_1.0.193.1_x64_Test\Add-AppDevPackage.ps1:388 char:13
+ Add-AppxPackage -Path $DeveloperPackagePath.FullName -DependencyPath ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (C:\Users\myuser....193.1_x64.appx:String) [Add-AppxPackage], IOException
+ FullyQualifiedErrorId : DeploymentError,Microsoft.Windows.Appx.PackageManager.Commands.AddAppxPackageCommand
Error: Could not install the app.
The Package Family Name (PFN) suffix (in your case hs446qhh7vdt4) is a hash of the certificate's subject (AKA subject name):
certutil -dump foo.pfx
Enter PFX password:
================ Certificate 0 ================
================ Begin Nesting Level 1 ================
Element 0:
Serial Number: xxxxxxxxxxxxxxxxx
Issuer: CN=Microsoft, O=Contoso, L=Redmond, S=Washington, C=US
NotBefore: 11/1/2016 12:00 AM
NotAfter: 11/1/2017 12:00 AM
Subject: CN=Microsoft, O=Contoso, L=Redmond, S=Washington, C=US <== THIS IS HASHED
If you make sure the new cert you generate has the same subject, you'll get the same PFN. Note that you might not be able to generate store certs from within Visual Studio (at the time of writing, it can't parse complex subjects like the one above with multiple 'parts' like CN=X, O=Y). In that case you'll have to create your own, but it must comply with the store validations.
Luckily, there's a simple command that generates the exact certificate you need. Open a Visual Studio developer prompt and run (one line):
makecert -sv foo.pvk -n "CN=Contoso, O=Contoso, L=Redmond, S=Washington, C=US"
foo.cer -b 11/01/2016 -e 11/01/2017 -r -cy end -a sha256 -eku 1.3.6.1.5.5.7.3.3
Make sure to replace the validity dates (no more than a year apart!) as well as the subject (taken from your previous cert using certutil -dump). The names of the output cert (cer) and private key (pvk) are meaningless. That command will generate foo.pvk and foo.cer, which you will then be able to combine to a pfx like so:
PVK2PFX -pvk foo.pvk -spc foo.cer -pfx foo.pfx
Another option for advanced generation
In case you have more advanced cert requirements, you should be able to use certreq (haven't tested it though). Create a file named cert.inf with the following contents:
[Version]
Signature = "$Windows NT$"
[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_CODE_SIGNING = "1.3.6.1.5.5.7.3.3"
szOID_BASIC_CONSTRAINTS2 = "2.5.29.19"
[NewRequest]
Subject = "CN=Contoso, O=Contoso, L=Redmond, S=Washington, C=US"
Exportable = true
HashAlgorithm = Sha256
KeyLength = 2048
RequestType = Cert
ValidityPeriod = "Years"
ValidityPeriodUnits = "1"
[Extensions]
%szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_CODE_SIGNING%"
%szOID_BASIC_CONSTRAINTS2% = "{text}"
Replace the subject and validity period, and adjust any advanced settings you need per the docs (or more likely found on the web). Then do the following:
certreq -new cert.inf cert.cer
Double-click the resulting cert.cer and install it to the Trusted Root Certificate Authorities store (either user or machine).
certreq -accept -user cert.cer OR certreq -accept -machine cert.cer (depending on the store you picked in the previous step).
Go to the Personal store in the cert manager (user or machine scope, depending on what you picked above) and find the cert you just installed. Double-click it and copy the serial number from the details tab (I encountered some voodoo here where the cert would only show up after a long time, or after I installed a different cert (with a different subject name).
certutil -exportpfx -p "YOUR_PFX_PASS" my SERIAL_NUMBER foo.pfx (replace the password and the serial number with their actual values)
You should now have a valid store pfx.
Yet another option for even more advanced generation
Use OpenSSL. Pretty sure it can do all the above and more, but I haven't tried it personally so you'll have to figure it out - and hopefully share here once you do!

Create your own certificate - "The Manifest Designer could not import the certificate"

I want to create certificate to signing my application:
c:\certcenter> makecert -sv demas.me.pvk -n "cn=demas.me" demas.me.cert -b 01/01/2014 -e 01/01/2015 -r
Succeeded
c:\certcenter> pvk2pfx.exe -pvk demas.me.pvk -spc demas.me.cert -pfx demas.me.pfx
When I am trying to select certificate in VS I get error message: "The Manifest Designer could not import the certificate".
Here is Publisher, Publisher name in the appmanifest and error message:
How can I fix this error ?
Step by step, instructions for one that can be found at https://learn.microsoft.com/en-au/windows/desktop/appxpkg/how-to-create-a-package-signing-certificate
and essentially are:
MakeCert /n publisherName /r /h 0 /eku "1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13" /e
expirationDate /sv MyKey.pvk MyKey.cer
Pvk2Pfx /pvk MyKey.pvk /pi pvkPassword /spc MyKey.cer /pfx MyKey.pfx [/po pfxPassword]
The options passed in to MakeCert are explained in the page, but here's an excerpt:
/r Creates a self-signed root certificate. This simplifies management for your test certificate.
/h 0 Marks the basic constraint for the certificate as an end-entity. This prevents the certificate from being used as a Certification Authority (CA) that can issue other certificates.
/eku Sets the Enhanced Key Usage (EKU) values for the certificate.
/e Sets the expiration date of the certificate.
(...)
Update:
Please be aware that when using MakeCert with expiration and start dates it uses the format of mm/dd/yyyy so 12/09/2018 is the 9th of December 2018, not the 12th of September 2018.

Can SSL cert be used to digitally sign files?

I want to ask a thing about digital signing I am not very sure.
Instead of creating a self signed certificate to use to sign some (PDF) files, I wanted to take my SSL cert which have my data already verified.
But the question is: Can a SSL cert be used to digital sign files or is it incompatible in some manner?
EDIT: To clarify, this question is not about how to sign PDFs, is only about if a SSL cert can be used (or converted in any way) to sign files.
To support digital signing certificate must have digitalSignature option in it's keyUsage field (and codeSigning option in it's extendedKeyUsage field if your want to sign programs with it).
Signing may be done with existing tools or manually (java example, you are not asking for it, but this code snippet might be useful anyway):
byte[] bytesToSign = loadMyData();
KeyStore ks = KeyStore.getInstance("pkcs12", "SunJSSE");
ks.load(new FileInputStream("cert.p12"), "passwd1".toCharArray());
PrivateKey privateKey = (PrivateKey) ks.getKey("myalias", "passwd2".toCharArray());
Signature sig = Signature.getInstance("SHA1withRSA", ks.getProvider());
sig.initSign(privateKey);
sig.update(bytesToSign);
byte[] signature = sig.sign();
To make your own not self-signed certificate with openssl see this SO answer.
Also curious about signing PDF's - aren't separate hash sums of these files enough in your case?
edit: if you want any sign, not exactly X.509 sign by existing tools, you can extract RSA key from your cert and do signing without bothering about keyUsage field.
At the core, the certificate is just a normal RSA public key that's been signed by several authorities.
So yes, definitely possible.
Though I don't know of any easy-to-use widespread tools for the end-user for this.
Yes, you can sign and verify the signature of files using SSL certificates
Here is an example:
SSLCERT='/XXXX/ssl/certs/fqdn.pem'
SSLKEY='/XXXX/ssl/private_keys/fqdn.pem'
# You might not need to specify a CA
CACERTFILE='/XXXX/ssl/certs/ca.pem'
# File to sign
FILE='YYYYYYY'
# Signs, needs ${SSLKEY} and ${FILE}
openssl dgst -sha512 -sign ${SSLKEY} -out ${FILE}.sha512 ${FILE}
# Then transfer the following files to another server:
# - ${CACERTFILE}
# - ${SSLCERT}
# - ${FILE}
# - ${FILE}.sha512
# Check the certificate is valid
openssl verify -verbose -CAfile ${CACERTFILE} ${SSLCERT}
# Extract the pub key from the cert
openssl x509 -in ${SSLCERT} -pubkey -noout > ${SSLCERT}.pub
# Check the signature
openssl dgst -sha512 -verify ${SSLCERT}.pub -signature ${FILE}.sha512 ${FILE}

add or create 'Subject Alternative Name' field to self-signed certificate using makecert

How can I create a certificate using makecert with a 'Subject Alternative Name' field ?
You can add some fields eg, 'Enhanced Key Usage' with the -eku option and I've tried the -san option but makecert doesn't like it.
This is a self-signed certificate so any method that uses IIS to create something to send off to a CA won't be appropriate.
An even easier way is to use the New-SelfSignedCertificate PowerShell commandlet, which includes a SAN by default. In a single command you can create the certificate and add it to the store.
New-SelfSignedCertificate -DnsName localhost -CertStoreLocation cert:\LocalMachine\My
Note that you need to run PowerShell as an administrator.
Makecert doesn't appear to support SANs so I created a certificate with SANs for use with IIS using OpenSSL. Check out my blog post about it:
IIS 7 provides some easy to use wizards to create SSL certificates,
however not very powerful ones. What I needed to do was to create SSL
certificates that included a x.509 V3 extension, namely subject
alternative names, a.k.a SANs. What SANs do is allow the website
certificate to validate incoming requests by more than one URL domain
name. This is really important when the web server is running web
services such as WCF services and when other web services connect to
them over SSL connections as with service oriented architectures.
Unless special code is added to the web services to override the
default SSL validation handler routines, the common name (CN) of the
certificate MUST match the incoming request URL domain. So if the
request was made using an FQDN, the certificate must have the FQDN as
a CN or a SAN, a IP address or just a hostname will cause an SSL
validation error and the connection will fail.
SANs to the rescue… SANs support, among other things, DNS names and IP
addresses. So by creating the certificate with SANs of the server FQDN
and IP address, it increases the ways that other web services can
connect.
There are a number of tools that can generate certificates:
makecert.exe, keytool.exe (java), selfssl.exe and openssl.exe. In
addition, starting with Windows Vista and Server 2008 Microsoft added
the CertEnroll API which can also create certificates programmatically
either through COM interfaces.
OpenSSL ended up doing exactly what I needed it to do. The process was
fairly straight forward.
Construct an OpenSSL config file.
[req] distinguished_name = req_distinguished_name x509_extensions =
v3_req prompt = no [req_distinguished_name] C = US ST = VA L =
Somewhere O = MyOrg OU = MyOU CN = MyServerName [v3_req] keyUsage =
keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth
subjectAltName = #alt_names [alt_names] DNS.1 = MyServerName DNS.2 =
10.0.1.34 IP.1 = 10.0.1.34 IP.2 = 192.167.20.1
Create x509 request with OpenSSL
openssl.exe req -x509 -nodes -days 730 -newkey rsa:2048 -keyout
C:\cert.pem -out C:\cert.pem -config C:\PathToConfigFileAbove.txt
Create a PFX containing the keypair
openssl.exe pkcs12 -export -out C:\cert.pfx -in C:\cert.pem -name "My
Cert" -passout pass:mypassword
Import the PFX into IIS using the import link in the server
certificates area.
Bind the certificate to the IIS websites.
And viola, we know have a SSL certificate for IIS with SANs so we can
connect using multiple domain names without certificate validation
errors.
Source: Creating certificates with SANs using OpenSSL by Andy Arismeti, Thursday, September 1, 2011
Update
The certificate generated using the below makecert method does not work reliably in all browsers, because it does not actually generate a "Subject Alternative Name".
If you examine the certificate you will see that it does not actually have a Subject Alternative Name field, but instead specifies multiple CN in the Subject field.
E.g.
Subject:
CN = blah.foo.corp
CN = blah
Whereas a real "SAN" cert would have something like:
Subject Alternative Name:
DNS Name=blah.foo.corp
DNS Name=blah
To understand the differences and history between the "Subject" field with "Common Name" and the "Subject Alternative Name" field, I recommend reading The (soon to be) not-so Common Name.
So it appears that makecert cannot be used to generate a true "SAN" cert, and you will need to use other tools, such as openssl.
Original Answer:
At least with the version of makecert that comes with Visual Studio 2012, you can specify multiple subjects, simply by specifying a comma separated list -n "CN=domain1, CN=domain2"
E.g. (from the technet blog Makecert.exe SAN and Wildcard certificate)
makecert -r -pe -n "CN=*.fabrikam.com, CN=*.contoso.com" -b 01/01/2010 -e 01/01/2100 -eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4 -ss my -sr localMachine -sky exchange -sp "Microsoft RSA SChannel Cryptographic Provider" -sy 12 -len 2048