Certificates - More than 1 serial number? - c#

weird :
I use this code to find certificate via c# by this code :
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var certificates = store.Certificates;
X509Certificate2Collection certificateCollection = store.Certificates.Find(X509FindType.FindBySerialNumber, "the Serial Number", false);
So I tested to see by an existing certificate :
but it didn't worked (as mentioned in the linked question). ( Also tried , remove spaces , capital etc... - non worked).
But when I played with it a bit I found another serial location :
this time just pasted the exact phrase "4e a1 ae 96 ec 1a b6 82 4e f6 23 9a 16 04 1a 51" and it worked .
What is going on here ?
why there are 2 different serial numbers and what are the differences between them ?
p.s. , However , not all certificates has the "Authority Key Identifier " , so there's still a problem finding by other properties...

I Think found a solution. ( I can't believe it )
copying the thumbprint number via copy+paste and pasted in cmd :
what the hell is this char ?
So I typed it manually char by char - and all good (+remove the spaces).
But still why there are 2 serials ?

The authority key identifier is an additional extension you can add to a certificate which indicates the issuer certificate which signed it. It isn't required because there is already the Issuer field which indicates the subject name of the issuer certificate but having the extension allows to more accurately specify it.

Related

Given an X509 certificate revocation list in PEM format, how do I convert that to a list of serial numbers of revoked certificates?

I am in C#, but I can also do this task manually on the command line if need be.
I have an X509 certificate revocation list in PEM format, generated by an HSM (hardware security module). Using openssl from a command line, I can see that the PEM file contains a collection of certificate serial numbers. I want to extract these serial numbers.
I have tried BouncyCastle, but the class X509Crl only exposes a method IsRevoked that takes an X509Certificate and returns a boolean. It refuses to give me the list of serial numbers.
I have looked at PKISolutions/pkix.net, but I cannot find any NuGet of it.
I have looked at Systems.Format.Asn1.AsnDecoder, but I don't understand how to use it.¨
Here is an example of my raw PEM:
-----BEGIN X509 CRL-----
MIIBcjCB+AIBATAKBggqhkjOPQQDAjBHMRwwGgYDVQQDDBMzU2hhcGUgS01TIFJv
b3QgMDAxMRYwFAYDVQQLDA1Ob25wcm9kdWN0aW9uMQ8wDQYDVQQKDAYzU2hhcGUX
DTIyMDkyMTE1NTA0OFoXDTI3MDkyMDE1NTA0OFowTjAlAhQbNlLUqfFJRnPUKF9N
gTAsM4lFOBcNMjIwOTIxMTU0OTI1WjAlAhQbNlLUqfFJRnPUKF9NgTAsM4lFORcN
MjIwOTIxMTU1MDQ4WqAwMC4wHwYDVR0jBBgwFoAUJlmqlqHSmhcu0m7aSgroirdg
dWYwCwYDVR0UBAQCAhABMAoGCCqGSM49BAMCA2kAMGYCMQCDRejYgOYC8zC91vqm
4D9X4H3IEjKQKfO3vQFd8iE4Q6ao+dBeIZ342nhosnePVxMCMQCHRXwB3eOkIv7u
1gzDvu9bXlsWNG8cgR5coTd0re/zRqN7cXuDlkR+h2mQdb0p/Eg=
-----END X509 CRL-----
Using openssl on a command line I can get this:
PS E:\Raven\2022-09-21> openssl crl -in E:\Raven\2022-09-21\3shape_kms_intermediate_crl_nonproduction_001-003.pem -noout -text
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN = 3Shape KMS Root 001, OU = Nonproduction, O = 3Shape
Last Update: Sep 21 15:50:48 2022 GMT
Next Update: Sep 20 15:50:48 2027 GMT
CRL extensions:
X509v3 Authority Key Identifier:
keyid:26:59:AA:96:A1:D2:9A:17:2E:D2:6E:DA:4A:0A:E8:8A:B7:60:75:66
X509v3 CRL Number:
4097
Revoked Certificates:
Serial Number: 1B3652D4A9F1494673D4285F4D81302C33894538
Revocation Date: Sep 21 15:49:25 2022 GMT
Serial Number: 1B3652D4A9F1494673D4285F4D81302C33894539
Revocation Date: Sep 21 15:50:48 2022 GMT
Signature Algorithm: ecdsa-with-SHA256
30:66:02:31:00:83:45:e8:d8:80:e6:02:f3:30:bd:d6:fa:a6:
e0:3f:57:e0:7d:c8:12:32:90:29:f3:b7:bd:01:5d:f2:21:38:
43:a6:a8:f9:d0:5e:21:9d:f8:da:78:68:b2:77:8f:57:13:02:
31:00:87:45:7c:01:dd:e3:a4:22:fe:ee:d6:0c:c3:be:ef:5b:
5e:5b:16:34:6f:1c:81:1e:5c:a1:37:74:ad:ef:f3:46:a3:7b:
71:7b:83:96:44:7e:87:69:90:75:bd:29:fc:48
Those serial numbers are what I want to extract. How can I do that, either in C# or on the command line?
This is not an answer but it may help. If you have OpenSSL then you can use a command like the following in terminal :
openssl x509 -noout -in fullceticatefilename -serial

.NET Framework x509Certificate2 Class, HasPrivateKey == true && PrivateKey == null?

I'm attempting to work with an X509 certificate that was originally imported into the CurrentUser keystore on a Windows 10 computer using the "Certificates" snap-in of an MMC. The same procedure has been tested on a Windows 8.1 computer with the same result.
Using the standard PowerShell PKI module, I'm getting an X509Certificate2 object using Get-Item:
$my_cert = Get-Item Cert:\CurrentUser\My\ADAA82188A17THUMBPRINTXXXXXXXXXXX
The output of $my_cert | fl * is as follows:
PSPath : Microsoft.PowerShell.Security\Certificate::CurrentUser\My\XXXXXXXXXXXXXXXXXXX
PSParentPath : Microsoft.PowerShell.Security\Certificate::CurrentUser\My
PSChildName : XXXXXXXXXXXXXXXXXXX
PSDrive : Cert
PSProvider : Microsoft.PowerShell.Security\Certificate
PSIsContainer : False
EnhancedKeyUsageList : {Secure Email (1.3.6.1.5.5.7.3.4), IP security user (1.3.6.1.5.5.7.3.7), Encrypting File
System (1.3.6.1.4.1.311.10.3.4), Document Signing (1.3.6.1.4.1.311.10.3.12)...}
DnsNameList : {My Name}
SendAsTrustedIssuer : False
EnrollmentPolicyEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty
EnrollmentServerEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty
PolicyId : {D52C406F-C279-4BF2-B7C2-EE704290DB3E}
Archived : False
Extensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid,
System.Security.Cryptography.Oid, System.Security.Cryptography.Oid...}
FriendlyName :
IssuerName : System.Security.Cryptography.X509Certificates.X500DistinguishedName
NotAfter : 4/15/2017 2:15:16 PM
NotBefore : 4/15/2016 2:15:16 PM
HasPrivateKey : True
PrivateKey :
PublicKey : System.Security.Cryptography.X509Certificates.PublicKey
RawData : {56, 130, 19, 252...}
SerialNumber : 4F0000002F700000000000000000000000
SubjectName : System.Security.Cryptography.X509Certificates.X500DistinguishedName
SignatureAlgorithm : System.Security.Cryptography.Oid
Thumbprint : XXXXXXXXXXXXXXXXXXX
Version : 3
Handle : 2241663016272
Issuer : CN=Issuing CA, DC=My, DC=Domain, DC=us
Subject : E=my.name#my.domain.us, CN=My Name
So HasPrivateKey == True, but PrivateKey == null. I've been trying to figure out how to gain access to the private key to perform encryption and decryption. The examples I've seen online all seem to indicate the PrivateKey property of the X509Certificate2 class should be readily available, but apparently I've missed something.
I've read similar questions here, such as Empty PrivateKey in x509certificate2, but none seem to resolve my issue. I've also read Eight tips for working with X.509 certificates in .NET by Paul Stovell, which was very enlightening, but ultimately didn't help. It did help me verify that the Private Key exists in the correct place and, as far as I can tell, with the correct permissions to be referenced by the x509Certificate2 class:
C:\Users\My.Name\AppData\Roaming\Microsoft\SystemCertificates\My\Keys
The name of the key file matches to the Subject Key Identifier on the certificate.
Edit:
The output of certutil -user -store my "Serial Number" is:
Serial Number: 4f000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Issuer: CN=Issuing CA, DC=My, DC=Domain, DC=us
NotBefore: 4/15/2016 2:15 PM
NotAfter: 4/15/2017 2:15 PM
Subject: E=my.name#my.domain.us, CN=My Name
Non-root Certificate
Template: Userv1, User v1
Cert Hash(sha1): ad ab 82 18 8a 17 4d 75 11 04 48 7c 43 43 d4 05 b9 74 c8 4c
Key Container = te-Userv1-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Unique container name: fcbba1aa0xxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Provider = Microsoft Software Key Storage Provider
Encryption test passed
CertUtil: -store command completed successfully.
What "key" piece of information am I missing here? Why isn't the private key conveniently referenced from the X509Certificate2 object? How do I gain access to it?
Your certutil information shows Provider = Microsoft Software Key Storage Provider which means that the private key is stored under Windows CNG, instead of Windows CryptoAPI (CAPI).
.NET 4.6 added the GetRSAPrivateKey (extension) method to facilitate the otherwise breaking change of letting the PrivateKey property return something which was not an RSACryptoServiceProvider (or DSACryptoServiceProvider). If you have access to that method (I'm not sure what version of the framework PowerShell uses) then it would solve your problem.
Two things to be aware of, though:
GetRSAPrivateKey returns a unique Disposable object each time. You should put it in a using statement/manually call Dispose when finished with it (as opposed to cert.PrivateKey, which isn't unique, so shouldn't be Disposed).
The sign/verify//encrypt/decrypt methods have moved down to the RSA base class (albiet with slightly different, more forward-looking, signatures).
This may indicate one of the following:
1) the private key is stored in the Key Storage Provider (rather than legacy crypto service provider) which is poorly supported by .NET and not supported by PrivateKey property of X509Certificate2 class at all. You can check this by running the following command:
certutil -user -store my "<CertSerialNumber>"
2) the private key is missing.
HasPrivateKey property doesn't necessary reflect the actual picture and may True for non-existent keys or False for existing keys. Run the certutil command above to make sure if the key is presented.
In the case if private key is presented, but the bindings are broken, you can try to restore bindings by running the following command:
certutil -user -repairstore my "<CertSerialNumber>"
I resolved the problem.
For some reason, .NET framework can't import private keys from files, however, it can import from the built-in windows store, this is because the PrivateKey method only supports RSA and DSA keys are per the Microsoft Spec: read the notes under "Remarks" section.
Anyhow, to get a PrivateKey object to return the key info, You need to do the following:
1) Import your P12 file into the Windows Keystore by double-clicking it.
2) Select "Import" when prompted into "Current User"
3) Make sure you select "Make Key Exportable",
if this option is not available then your certificate has no private
key
.
4) Select "Automatically place into store"
5) Write the following code to retrieve your certificate:
Dim CertDataInfo As System.Security.Cryptography.X509Certificates.X509Certificate2
Dim Store As New System.Security.Cryptography.X509Certificates.X509Store("MY", Security.Cryptography.X509Certificates.StoreLocation.CurrentUser)
Store.Open(Security.Cryptography.X509Certificates.OpenFlags.ReadOnly)
Console.writeline (Store.Certificates.Count)
For I = 0 To Store.Certificates.Count - 1
If Store.Certificates.Item(I).FriendlyName = "Heider Sati's Cert(48F57XTHVE)" Then
CertDataInfo = Store.Certificates.Item(I)
End If
Console.writeline ("Cert: " & Store.Certificates.Item(I).FriendlyName)
Next
Store.Close()
If CertDataInfo.PrivateKey Is Nothing Then
MsgBox("NULL")
Else
MsgBox("YES")
End If
6) Run the code, if you get a YES then the private key is not NULL (or NOTHING), which is what you are looking for.
If you load the same certificate directly from the file, the Private key will always be NOTHING / NULL , but the HasPrivateKey will say YES, which means (I know there is a key, but yet, I don't know how to understand it. When you import it into the Windows store, then Windows does translate it into a .NET-Compatible format.
I hope this helps.

Identification of private key in Pkcs11Interop.PDF library

I am trying to setup up an example application with the Pkcs11Interop.PDF extension. I am unfortunately getting a System.ArgumentNullException setting the ckaId. What would work here? I tried different numbers here which all gave me a System.ArgumentOutOfRangeException.
The setup is using the VirtualCryptoki-64-1.0.6.7.exe application to simulate a Smartcard.
The troubling call is:
pkcs11RsaSignature = new Pkcs11RsaSignature(libraryPath, tokenSerial, tokenLabel, pin, ckaLabel, ckaId, hashAlgorithm);
The hash algorithm I use is:
HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256;
Update after using the pkcs11-tool:
The content of the virtual card is:
C:\Program Files\OpenSC Project\OpenSC\tools>pkcs11-tool.exe --module "C:\windows\System32\vcki.dll" --list-slots --list-objects --login --pin 1234
Available slots:
Slot 0 (0xd47db04d): Virtual Smart Card Reader
token label: Virtual SC-A0101010101
token manuf: Cryptware
token model: VirtualSmartCard
token flags: rng, login required, PIN initialized, token initialized, other flags=0x200
serial num :
Using slot 0 with a present token (0xd47db04d)
Certificate Object, type = X.509 cert
label: ibisit
ID: 4a656e73204b6175666d616e6e
Public Key Object; RSA 1024 bits
label: ibisit
ID: 4a656e73204b6175666d616e6e
Usage: encrypt, verify
Private Key Object; RSA
label: ibisit
ID: 4a656e73204b6175666d616e6e
Usage: decrypt, sign
warning: PKCS11 function C_GetAttributeValue(ALWAYS_AUTHENTICATE) failed: rv = CKR_ATTRIBUTE_TYPE_INVALID (0x12)
Public Key Object; RSA 1024 bits
label: ibisit
ID: 4a656e73204b6175666d616e6e
Usage: encrypt, verify
Private Key Object; RSA
label: ibisit
ID: 4a656e73204b6175666d616e6e
Usage: decrypt, sign
warning: PKCS11 function C_GetAttributeValue(ALWAYS_AUTHENTICATE) failed: rv = CKR_ATTRIBUTE_TYPE_INVALID (0x12)
The parameters I use are:
string libraryPath = #"C:\Windows\System32\vcki.dll";
string tokenSerial = null;
string tokenLabel = #"Virtual SC-A0101010101";
string pin = #"1234";
string ckaLabel = #"ibisit";
string ckaId = "4a656e73204b6175666d616e6e";
HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256;
I am unfortunatly getting a Net.Pkcs11Interop.PDF.ObjectNotFoundException setting the ckaId. Changing the pin gives me a different exception so I am definetely accessing the right device here.
Update after switching to SoftHSM:
jariq stated that too many objects with the same id were there problem here. Unfortunately the Virtual Key Explorer would not let me delete any object so I switched to SoftHSM (which I was using at the beginning). I am getting "Certificate with label "ibis-it key" and id "A1B2" was not found". I suppose the problem here is that this virtual card only holds a RSA keypair not a certificate.
The output of the pkcs11-tool is:
C:\Program Files (x86)\OpenSC Project\OpenSC\tools>pkcs11-tool.exe --module "C:\SoftHSM\lib\libsofthsm.dll" --list-slots --list-objects --login --pin smart
Available slots:
Slot 0 (0x0): SoftHSM
token label: SoftHSM
token manuf: SoftHSM
token model: SoftHSM
token flags: rng, login required, PIN initialized, token initialized, other flags=0x40
serial num : 1
Using slot 0 with a present token (0x0)
Public Key Object; RSA 2048 bits
label: ibis-it key
ID: a1b2
Usage: verify
Private Key Object; RSA
label: ibis-it key
ID: a1b2
Usage: sign
The Problem is that SoftHSM only imports PKCS#8 (RSA) key pairs, so there will never be a certificate here. I suppose you have been using it with RSA key pairs but not with certificates.
Parameters passed to the constructor of Net.Pkcs11Interop.PDF.Pkcs11RsaSignature class identify following things:
which PKCS#11 library should be used (libraryPath)
which token/smartcard stores the private key (tokenSerial and/or tokenLabel)
which private key should be used for signing (ckaLabel and/or ckaId)
which hash algorithm should be used during signature creation (hashAlgorithm)
If you know which PKCS#11 library should be used to access the smartcard then you can determine correct values for the rest of the parameters i.e. by running pkcs11-tool utility which is bundled with OpenSC middleware. Please find below the exact command and the output generated for my testing card (important parts are highlighted with bold text):
C:\Program Files (x86)\OpenSC Project\OpenSC\tools>pkcs11-tool.exe --module cardos11.dll --list-slots --list-objects --login --pin 11111111
Available slots:
Slot 0 (0x1): SCM Microsystems Inc. SCR33x USB Smart Card Reader 0
token label : Pkcs11Interop
token manufacturer : www.atos.net/cardos
token model : CardOS V4.3B
token flags : rng, login required, PIN initialized, token initialized, other flags=0x800
hardware version : 102.63
firmware version : 200.8
serial num : 7BFF2737350B262C
Using slot 0 with a present token (0x1)
Private Key Object; RSA
label: John Doe
ID: ec5e50a889b888d600c6e13cb0fdf0c1
Usage: sign
Certificate Object, type = X.509 cert
label: John Doe
ID: ec5e50a889b888d600c6e13cb0fdf0c1
Based on this output these are the correct values of individual parameters for this card:
libraryPath="cardos11.dll"
tokenSerial="7BFF2737350B262C" and/or tokenLabel="Pkcs11Interop"
ckaLabel="John Doe" and/or ckaId="ec5e50a889b888d600c6e13cb0fdf0c1"
Hope this helps.
Update for ObjectNotFoundException:
You are getting ObjectNotFoundException because there are two private keys with the exactly same label and ID stored in your token and therefore Pkcs11RsaSignature class cannot be sure which one should be used for signature creation. Just delete or rename one of them and it should be working.
Update for SoftHSM:
You can import PKCS#8 private key to SoftHSM with softhsm.exe tool:
C:\SoftHSM\bin>softhsm.exe --import doe.key --slot 0 --label "John Doe" --pin 11111111 --id "ec5e50a889b888d600c6e13cb0fdf0c1"
The key pair has been imported to the token in slot 0.
You can import DER encoded X.509 certificate to SoftHSM with pkcs11-tool.exe tool:
C:\SoftHSM\bin>"c:\Program Files (x86)\OpenSC Project\OpenSC\tools\pkcs11-tool.exe" --module libsofthsm.dll --login --pin 11111111 --write-object doe.der --type cert --label "John Doe" --id "ec5e50a889b888d600c6e13cb0fdf0c1"
Using slot 0 with a present token (0x0)
Created certificate:
Certificate Object, type = X.509 cert
label: John Doe
ID: ec5e50a889b888d600c6e13cb0fdf0c1
Just make sure you will import the certificate with the same ID as the ID of private key.

How to extract RSA parameters from iOS SecKeyRef?

I'm calling the iOS SecKeyGeneratePair method to generate an RSA key pair. Now I want to extract the RSA parameters from it (both public and private data). How can I do that?
I've found the CryptoExercise sample but I don't see that it's actually exporting keys to their raw data. Besides, it's Objective-C which I am really struggling to grok.
I'm doing this in a Xamarin.iOS (C#) mobile app so I need my ultimate solution to be written in C# by calling the necessary interop APIs into iOS (just like my call to SecKeyGeneratePair).
For those familiar with Xamarin, yes, I know I can use new RSACryptoServiceProvider() to do it much more easily. The difference is 2-3 orders of magnitude perf improvement when I use native APIs for RSA key generation (and even the encryption bit itself). So while I must use native APIs for the RSA work, I also need to get the raw data out so that I can be cross-platform.
AFAIK you cannot directly extract the parameters. There was some talk on the Apple developer forums about this (you might want to check). Sadly the Apple engineer answer was the assumptions (about the posted code) were implementation details and subject to change at any time.
Still you might be able to do this indirectly using the available API, e.g. export it as a PKCS#12 and then get the RSA parameters from it.
UPDATE: upon verification you can only import PKCS#12 - so this would not help exporting the private key. I'm back to the there's no supported way of doing it. The only safe option, beside the use of managed code, I can think of is to include native code (3rd party library) to generate the keypairs.
I once tried something similar (it was import, not export) but the time required for the extra operations made my code slower than using only C#. Your situation is different so YMMV.
note: it seemed to me that the keychain access (which is out of process, encrypted...) caused much of the slowdown. It was not worth importing a public key for a one-time use - but if you're (re)using it multiple time then the (one-time) cost might be acceptable to you.
The SecKeyGeneratePair is an older API replaced by SecKeyCreateRandomKey that's only available as of iOS 10. So I will answer using the older functions that the question asks about. I'll stick to Core Foundation APIs for interoperability with C#.
You can export the public and private raw key data by adding it to the keychain and returning it as data bytes. Here's an example:
//Convert key object into data
SecKeyRef givenKey = publicOrPrivateFromSecKeyGeneratePair;
static const uint8_t publicKeyIdentifier[] = "com.company.myTempRSAKey"; //make it unique per key
CFDataRef publicTag = CFDataCreate(kCFAllocatorDefault, publicKeyIdentifier, sizeof(publicKeyIdentifier));
if (publicTag)
{
OSStatus sanityCheck = noErr;
CFDataRef publicKeyBits = NULL;
//Create a dictionary info object describing that we are using RSA
CFMutableDictionaryRef queryPublicKey = CFDictionaryCreateMutable(kCFAllocatorDefault, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (queryPublicKey)
{
CFDictionaryAddValue(queryPublicKey, kSecClass, kSecClassKey);
CFDictionaryAddValue(queryPublicKey, kSecAttrApplicationTag, publicTag);
CFDictionaryAddValue(queryPublicKey, kSecAttrKeyType, kSecAttrKeyTypeRSA);
CFDictionaryAddValue(queryPublicKey, kSecAttrKeyClass, kSecAttrKeyClassPublic); //for public or:
//CFDictionaryAddValue(queryPublicKey, kSecAttrKeyClass, kSecAttrKeyClassPrivate); //for private
CFDictionaryAddValue(queryPublicKey, kSecAttrAccessible, kSecAttrAccessibleWhenUnlockedThisDeviceOnly); //other options...
CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 7, queryPublicKey);
if (attributes)
{
// Temporarily add key to the Keychain, return as data:
CFDictionaryAddValue(attributes, kSecValueRef, givenKey);
CFDictionaryAddValue(attributes, kSecReturnData, kCFBooleanTrue);
CFTypeRef result = NULL;
sanityCheck = SecItemAdd(attributes, &result);
if (sanityCheck == errSecSuccess)
{
publicKeyBits = (CFDataRef)result; // Use the RAW key here
// Remove the temp key from the Keychain
sanityCheck = SecItemDelete(queryPublicKey);
if (sanityCheck != errSecSuccess)
{
//... Error deleting temporary public key from keychain
}
}
// else - failsafe code if key exists, try to delete first and then add item etc.
CFRelease(attributes);
}
CFRelease(queryPublicKey);
}
CFRelease(publicTag);
}
This gets you the raw data. It's raw because it's missing the header that most systems outside of Apple expect. The ASN.1 OID value for RSA public keys followed by a terminating NULL byte, for example.
//HEX: 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00
/*
SEQUENCE {
OBJECTIDENTIFIER 1.2.840.113549.1.1.1 (rsaEncryption)
NULL
}
*/
So if you're looking for the raw data you have it. If by "parameters" you're trying to extract the modulus and exponent from the raw data, you can do that too (ex. a bit stream: mod + exp). Let me know if that is what you're after.

Why do I get Cryptography_CSP_NoPrivateKey when using IIS but not when using VS development server?

I'm doing a web application that utilizes an external web service. This external web service requires me to sign each of my requests. So I'm using WebServicesClientProtocol class and .NET 2.0 by first consuming the external web service and then manually edit the Reference.cs file and change the extended class from System.Web.Services.Protocols.SoapHttpClientProtocol to Microsoft.Web.Services2.WebServicesClientProtocol. Then in the Page_Load method I have the following code:
try
{
// Create the ws endpoint
var uriServiceAddress = new Uri("urn:something-wse:something_NNNN");
var uribuilderViaRouter = new UriBuilder("http://xx.xxx.xx/SrvXXX_NNNN/Test.asmx");
var endpointReference = new EndpointReference(uriServiceAddress, uribuilderViaRouter.Uri);
// Create the ws client
var client = (WebServicesClientProtocol) new Test.Something();
client.Destination = endpointReference;
// Read the certificate from MyStore on LocalMachine
X509CertificateStore localStore = X509CertificateStore.LocalMachineStore(X509CertificateStore.MyStore);
X509SecurityToken securityToken = null;
if (!localStore.OpenRead()) throw new Exception("Unable to open localstore for read");
X509CertificateCollection certificateCollection = localStore.FindCertificateBySubjectString("email#subject.test");
if (certificateCollection.Count == 0) throw new Exception("Unable to obtain security token.");
securityToken = new X509SecurityToken(certificateCollection[0]);
localStore.Close();
// Attach the security toekn to the client request
client.RequestSoapContext.Security.Tokens.Add(securityToken);
client.RequestSoapContext.Security.Elements.Add(new MessageSignature(securityToken));
// Set the timeouts
client.RequestSoapContext.Security.Timestamp.TtlInSeconds = 2 * 60;
client.Timeout = 60 * 10 * 1000; // 10 mínútur ættu að duga í flest.
// Call the test function
DataSet set = ((Test.Something)client).searchMethod("Parameter 1", "Parameter 2");
Label1.Text = User.Identity.Name+ " worked! " + set.Tables.Count + " tables!";
}
catch (Exception exc)
{
Label1.Text = User.Identity.Name + " exception: " + exc.ToString();
}
This works fine when I run this using the Visual Studio Development Server but when I change to IIS it stops working and I get the ugly Cryptography_CSP_NoPrivateKey exception.
1) I have already read the Certificate properly into LocalMachine/MyStore using MMC and then I change the private key permissions using WSE 2.0 SP3 so that Everyone has full access to it. You can see this from here:
alt text http://www1.ruedenet.is/files/CertError1.png
2) I also set the property so that the Visual Studio Development Server is used when I debug the application:
alt text http://www1.ruedenet.is/files/CertError2.png
3) Then I run it and get a nice result:
alt text http://www1.ruedenet.is/files/CertError3.png
4) However, when I change the property to use IIS (and have VS create the Virtual Directory) like this:
alt text http://www1.ruedenet.is/files/CertError4.png
5) I also change the authentication method in IIS so that I get logged on (no reason for this really):
alt text http://www1.ruedenet.is/files/CertError5.png
6) So I get asked for a windows logon:
alt text http://www1.ruedenet.is/files/CertError6.png
7) And then my page runs and produces the error:
alt text http://www1.ruedenet.is/files/CertError7.png
If you could help me with this I would surely appreciate it. I have already spent hours on it and I don't want to spend more time if I'm making a fundamental error that you guys can see. BTW: I'm developing using Visual Studio 2008 on Windows Server 2008 with UAC turned off :-)
Really looking forward to hearing from you guys. Thanks.
:-)
I have solved this issue in a couple of steps:
1) I changed the user of the Default Application Pool to my username ...
alt text http://www1.ruedenet.is/files/ErrorFix1.png
... and that worked. I changed the user of the application pool back to NETWORK SERVICE and it didn't work again. This told me that the problem had something to do with the NETWORK SERVICE user. So I went back to looking for what could be the problem with the permissions of this user.
2) When browsing and reading the web I found Tim Jacobs' blogpost App-V 4.5 Certificate Galore at http://timjacobs.blogspot.com/2008/11/app-v-45-certificate-galore.html. Well, there wasn't anything new in it until at the end where he talks about the storage location of the private key on the disk. So I ran the FindPrivateKey.exe tool, ...
C:\MyTools>FindPrivateKey.exe My LocalMachine -t "8c 1a e6 1b 6d f2 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58"
Private key directory:
C:\Users\alfred\AppData\Roaming\Microsoft\Crypto\RSA\S-1-5-21-3612370315-2559787 071-3412320394-1135
Private key file name:
b3765d4123902371ea91c5c9a521932e_96ce3a90-5634-44e6-8aa2-acb123b8b3bf
... which tells me that the location of the private key is in the C:\Users\alfred\... directory and the NETWORK SERVICE user probably doesn't have access in to this directory!!!
3) I therefore followed Tim's suggestion to use MMC to export the certificate & private key from the Local Computer/Personal/Certificates and then import it into Local Computer/Trusted Root Certificate Authorities/Certificates. After having exported, FindPrivateKey.exe reported, ...
C:\MyTools>FindPrivateKey.exe My LocalMachine -t "8c 1a e6 1b 7d f1 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58"
FindPrivateKey failed for the following reason: No certificates with key '8c 1a e6 1b 7d f1 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58' found in the store.
... which tells me the export worked. After importing and copy pasting it back to Local Computer/Personal/Certificates I get...
C:\MyTools>FindPrivateKey.exe My LocalMachine -t "8c 1a e6 1b 7d f1 f8 18 c8 26 b6 fa cd 60 fd 94 c7 a1 96 58"
Private key directory:
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys
Private key file name:
b3765d4d5a902371ea91c5c9a521932e_96ce3a90-5634-44e6-8aa2-acbaccb8b3bf
...and now the private key is in a public place, the C:\ProgramData\... directory. I then changed the private key permissions of the NETWORK SERVICE user to Full Access using the X509 Certificate Tool as I had done before.
And now it works!!!
I just can't thank you enough for your blogpost Tim. Thank you.

Categories

Resources