[Mono-dev] Adding privatekey support to X509Store
sebastien.pouliot at gmail.com
Wed Oct 20 15:31:32 EDT 2010
It's a bit long and (likely) boring but history lessons are rarely fun
(and I'm not the kind of guy to try to rewrite history to make it better
or even funnier ;-)
On Wed, 2010-10-20 at 19:52 +0200, Pablo Ruiz wrote:
> Here's another question to the list:
> * What's exactly the purpose of KeyPairPersistence is? It looks
> like some sort of pseudo KeyContainer implementation which
> it's used by RSACryptoServiceProvider to save keys to disk..
> however I'm still trying to look it's relationship to
Hehe, you have to go back to CryptoAPI 1.0 days to see this
relationship ;-) i.e. before x.509 support there was only keypairs
persistence service offered by the (windows) OS (via CAPI).
By some (likely unrelated) circumstances the .NET framework 1.0 (and
1.1) also only exposed this via CspParameters class (even if CryptoAPI
2.0 was available on all .NET platforms at the time).
Once CryptoAPI 2.0 (supporting X509) became available new (similar in
design) certificate stores where exposed. The same stores were also
exposed (much later) in .NET 2.0.
A design decision was made (likely for compatibility) that the
certificates private keys (when available) were to be stored in the
"original" keypair stores. However this is (mostly) done by magic - i.e.
it's not exposed by the API, the association process is a black box.
That bit of magic gets exposed when you (under windows) loads a
certificate (e.g. a .cer, without a private key, form disk) and
"automagically" get the private key to sign (if available because the
certificate also exists in a store and the private key was available
when it was installed). It seems benign but quite a few applications
depends on this.
More details inline...
> On Wed, Oct 20, 2010 at 4:06 PM, Pablo Ruiz <pablo.ruiz at gmail.com>
> Hi Sebastien,
> Great you replied, as you were the first one on my (short)
> list of 'people to ask in case of emergency' ;)
> Actually my (medium-long term) goal it's adding support for
> non-software based crypto devices to mono, however I know this
> it's not a simple task to undertake, so I will try to
> implement it on a step-by-step basis.
Key/cert store association is unlikely to help this scenario. By that I
mean the solution for this HSM scenario is to shield even more the
private key from the software side (while the association will require
the opposite). Of course you're welcome to implement both :-)
> In fact, here it's, an initial short list of what I would like
> to do, it's an initial list of goals, which has not
> been analyzed in deep.. so any comment/ideas/proposals would
> be great:
> * Adding (software-based) privateKey support to
> X509Stores, so one can get an X509Certificate2 from an
> store and sign with it, just the same way it works in
X509Certificate2 is smart enough to do this with PKCS12 files - which is
a store by itself (and IMO a much better one since it is, or can be,
password protected and nothing gets hidden into store that the user
cannot see, nor manage efficiently).
> * Adding privateKey support to X509Stores, but using
> some sort of provider model, similar to what has been
> done at mono's System.Messaging, allowing user to
> switch certificate store's (or
> *CryptoServiceProvider's) implementation.. (and or
> allowing us to have different x509store mechanism on
> different OSs)
That's mostly all existing. What's missing is the final glue between the
CspParameters, the KeyPersistence and the X509 stores. Most importantly
is making sure the tooling exists to replace the "magic" of windows ;-)
> * Implementing one of such x509store/CSP sub-systems
> which allows to use a hardware HSM, maybe by using
> pkcs11 or openssl-engine under the hood.
This should be done via the CspParameters class keeping this, source
wise, as close as possible with windows (for application code). This is
where the previous "glue" should be refactored (along the existing code)
as the default (managed) implementation.
> I already have knowledge on x509 programing on both win32 (c
> ++/.net) and linux/openssl, however, as you said, how things
> are assembled in mono can be challenging as AFAIK there's also
> support for MacOSX/iPhone/etc.
That's not the real challenge. Right now we're missing few features, but
we're compatible with existing .net code. So the key is to fill the
missing features, without breaking existing feature compatibility and
ensuring the new feature do not require mono-specific code (inside
Otherwise it's much simpler to start from scratch and develop a custom
RSA class on top of your HSM.
> As such, being able to add support for (software based)
> privateKey handling to X509Stores looks like an not-so-hard
> initial task
agreed, it should not be hard since pkcs12 already provides that :)
> which will allow me to start hacking around Mono.Security &
> System.Security so I can learn how all those bits are put in
> place on mono.
Try to avoid touching Mono.Security.dll. Most of it (X509 wise) was
designed to fill the missing features in FX 1.x for Mono itself. Fx 2.0
introduced (very similar*) classes to do most of the same things. For
compatibility (both to Mono.Security.dll users and FX2+ apps) most of
the code should reside in the new namespaces (and not in Mono.Security).
* I'd like to claim genius but honesty compels me to say our original
model was to be compatible with windows so... ;-)
> I have already started hacking a bit, and by now I have it's
> just added (to Mono.Security.dll) the ability to store private
> key's along with public x509 certificate files, however I have
> a few doubts which:
> * My initial idea was extending
> Mono.Security.X509.X509Store::Import so if a
> certificate with
warning! you cannot change the public API (beside adding new overloads)
> * exportable parameters are passed as input, it will
> create (along with the DER certificate file) a new
> file ($UniqueName$.key), which will contain the PKCS8
> privateKey (encrypted using ProtectedData.Protect).
> Obviously when accessing the certificate, the oposite
> operation will be done to return a certificate with
> it's corresponding privateKey if available.. However,
> I'm not completelly sure about this approach.. ¿any
> recomendation in this area?
KeyPersistance should be used and a link (well likely a file for windows
compatibility) should point from the cert store to the key store.
> * Also, I would like to control which key's cannot be
> exported (just the same as on win32), where would you
> store this infomartion (a bool or something indicating
> that a key it's exportable).. ¿a $UniqueName$.xml file
> along with cert and key?
Key export is a gray area - at least for the default store. i.e. we can
flag keys (as non-exportable) but we have no way (e.g. reflection) to
enforce the condition. IMO we better clearly states this is not
supported than "faking" the feature (and being "transparently" insecure
I suggest that the API provide the possibility (for future store) but
simply throws NotSupportedException on the default managed/software
> * Also, I have doubts about how to associate certs and
> privateKeys within the store. My current solution
> looks great for software based privateKey, however,
> if/when at some point we do support hardware based
> privateKey.. how can our X509Store know that a
> certificate's privateKey it's 'usable' by using one
> specific x509-provider? Just storing this info on an
> ¿XML? file along with the certificate itself seems a
> viable solution, but I would like to share ideas with
The CspParameters information should (well even must) be enough to
complete the association. That's the only way to provide compatibility
Of course some configuration/mapping options can be available on the
> * As far as I can see, a few Mono.Security's classes
> (X509Store among them) are duplicated at
> mcs/class/corlib/Mono.Security.X509/.. ¿should I copy
> my updated classes back to corlib/Mono.Security.X509?
That was a workaround for some build/cvs limitations we had 5 years ago.
For the time being you'll need (for testing) to duplicate them. However
this is something I think we can fix.
> * Regarding RSAManaged and RSACryptoServiceProvider, I
> know that on MS side of things, X509Certificate2 has a
> CAPI binding (via PrivateKey property) to the CSP
> store which holds the certificate (and it's
> privateKey).. Right now I have not made a deep
> analisys of what it's the best path to provide the
> same functionality, and any pointer on this subject
> would be great ;)
It's a bit more complex. The original FX had a very good crypto design
but, at some point (and for reasons I can only guess) they decided to
ignore it*. In this case it means that RSACSP has severe limitations
(like not providing EncryptValue) that requires us (e.g. when running
Mono.Security on .NET/windows) to use RSAManaged.
Anyway this should not be a showstopper (but something to keep in
* There was a whole crypto class that simply did not work on FX 1.x
because RSACryptoServiceManager did not use it.
> This is what I have by now.. but undoubtly more issues will
> come.. ;)
I suggest you define a complete scenario (or a few ones) before
modifying too much code. Past experiences (with pkcs11 and capi/csp) has
prove to me that they don't map very well in many cases (or at least
that theory about them is much easier than hacking them ;-)
IOW I think it would be better (and much easier for you) to know which
HSM (or at least API) you want to bind with first, then refactor the
existing key/cert store code based on this (and community feedback).
> I'm also available at irc (#mono) and I guess I will ask you
> some questions there at some point, however, I will submit of
> our conclusions here, of course ;)
Great :) let's leave a trace of this for future generations ;-)
> On Wed, Oct 20, 2010 at 2:33 PM, Sebastien Pouliot
> <sebastien.pouliot at gmail.com> wrote:
> Hello Pablo,
> On Wed, 2010-10-20 at 00:23 +0200, Pablo Ruiz wrote:
> > Hi,
> > I'm thinking on adding privateKey support for
> > so it can be (later) used as part of
> > System.Security.Cryptography.X509Certificates (on
> 2.0+). This is one
> > of the x509 related improvements I would like to add
> to mono's trunk.
> > However, I would like to discuss (by email and/or
> irc?) some of the
> > details first with some core member (some sort of
> mentoring) in order
> > to start in a good direction.
> You can either discuss this here, on this
> mailing-list, since it will
> leave a google-able trace of the discussion. Otherwise
> you can try to
> ping me on IRC (e.g. #monodev on GIMPNet) and we can
> post a resume later
> There are quite a few things to be aware in order to
> implement this
> (since it involves OS level features, tools and the
> class libraries). I
> think the best step would be, for you, to describe
> your understanding of
> the issues and I'll fill the blanks (in any :-).
More information about the Mono-devel-list