所有不同的X509KeyStorageFlags的基本原理是什么? [英] What is the rationale for all the different X509KeyStorageFlags?

查看:194
本文介绍了所有不同的X509KeyStorageFlags的基本原理是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,一位同事又发现了另一个与此有关的错误!我发现这些标志确实让我感到沮丧,因为如果您在实例化X509Certificate2对象,导出它们或将它们保存在X509Store中时,将它们弄得有些错误,则可能会遇到各种奇怪的错误,例如:

Today, a colleague hit yet another bug related to these! I've found these flags really frustrating in past myself, because if you get them slightly wrong while instantiating X509Certificate2 objects, or exporting them, or saving them in an X509Store you can land in situations with all sorts of weird bugs such as:


  • 意外地无法告诉NETSH.exe或ASP.net使用某个SSL证书(根据其指纹),即使您拥有该证书在您的机器存储中

  • 意外地,您可以导出证书数据,但是使用.Export()

  • 会意外地导出证书数据,而无需使用私钥开始在较新的Windows版本上失败,显然是因为您没有使用正确的标志

是的,它们已被记录,并且所有(和一些文档似乎似乎很有意义),但是为什么它必须这么复杂?

Yes, they're documented and all (and some of the documentation almost seems to make sense), but why does it have to be this complicated?

推荐答案

主要是,它具有今天变得如此复杂,因为昨天如此繁复,没有ne提出了一些更简单的方法。

Mainly, it has to be this complicated today because it was this complicated yesterday and no one has come up with anything simpler.

在这里我无法提出线性叙述,因此请耐心地进行必要的编织。

I can't come up with a linear narrative here, so please endure the weaving back and forth that's required.

虽然我不能完全说出PFX的起源,Windows函数的名称就有一个线索来读取和编写它们: PFXImportCertStore PFXExportCertStore 。它们包含许多单独的实体(证书,私钥和其他东西),可以使用属性标识符进行相互关联。它们似乎被设计为整个证书库(如所有CurrentUser\My)的导出/导入机制。但是,由于一种存储是内存存储(任意集合),. NET导入/导出很有意义,但是(在.NET之前)却带来了一些麻烦。

While I can't fully say what the origins of the PFX are, there's a clue in the names of the Windows functions to read and write them: PFXImportCertStore and PFXExportCertStore. They contain a lot of separate entities (certs, private keys, and other stuff) that can use property identifiers to interrelate. They're seemingly designed to be an export/import mechanism for an entire cert store, like all of CurrentUser\My. But since one kind of store is the "memory store" (an arbitrary collection), .NET import/export make sense, but some complication comes in (from before .NET).

Windows支持私钥的许多不同位置,但是对于旧的加密API,它们归结为4部分寻址方案:

Windows supports lots of different places for private keys, but for the legacy crypto API they come down to a 4-part addressing scheme:


  • 密码提供者的名称

  • 密钥容器的名称

  • 如果是机器相关密钥或用户相关密钥的标识符

  • 如果这是签名密钥或交换密钥的标识符。

  • The name of the cryptographic provider
  • The name of the key container
  • An identifier of if this is a machine-relative key or a user-relative key
  • An identifier of if this is a "signature" key or an "exchange" key.

对于CNG,这简化为三部分方案:

This got simplified to a 3-part scheme for CNG:


  • 存储引擎的名称

  • 密钥的名称

  • 如果这是相对于机器的标识符键或用户相对键。

CAPI和CNG均支持与命名密钥直接交互。因此,您创建了一个名为 EmailDecryption的密钥。系统上的另一个用户创建了相同名称的密钥。应该行吗?我们很可能会。所以,真主党,确实如此!单独的密钥,因为它们是在与创建它们的用户绑定的上下文中保存的。

CAPI and CNG both support directly interacting with named keys. So you create a key named "EmailDecryption". Another user on the system creates a key of the same name. Should that work? Well, probably. So, huzzah, it does! Separate keys, because they're held under contexts tied to the user who made them.

但是现在您想要一个可以供多个用户使用的密钥。这不是您通常想要的东西,因此不是默认设置。这是一个选择。 CRYPT_MACHINE_KEYSET 标志诞生了。

But now you want a key that can be used by multiple users. It's not the thing you normally want, so it's not the default. It's an option. The CRYPT_MACHINE_KEYSET flag is born.

我在这里继续说,我已经听说过直接现在不鼓励使用命名键; CAPI / CNG团队更喜欢使用GUID命名的密钥,并且您可以通过证书存储与它们进行交互。

I'll go ahead and say here that I've heard that the direct usage of named keys is now discouraged; the CAPI/CNG team much prefers GUID-named keys and that you interact with them via the cert stores. But it's part of the evolution.

PFXImportCertStore复制所有证书从PFX到提供的商店。它还会导入( CryptImportKey 或<一个href = https://docs.microsoft.com/zh-cn/windows/desktop/api/bcrypt/nf-bcrypt-bcryptimportkey rel = noreferrer> BCryptImportKey ,具体取决于它的想法需求)。然后,对于它导入的每个密钥,它都会找到匹配的证书(通过PFX中的属性值),并在证书存储表示中为这是我的4部分标识符设置一个属性(CNG密钥仅设置了第4个部分为0);

PFXImportCertStore copies all of the certificates from the PFX into the provided store. It also imports (CryptImportKey or BCryptImportKey, depending on what it thinks it needs). Then, for each of the keys that it imported it finds (via property values in the PFX) the matching certificate, and sets a property on the cert store representation for "this is my 4-part identifier" (CNG keys just set the 4th part to 0); which is really all that the cert knows about its private key.

(PFX是一种非常复杂的文件格式,只要没有怪异部分得到

(PFX is a very complicated file format, this description is true provided none of the "weird parts" get utilized)

Windows私钥将永久存在,或者直到有人将其删除为止。

Windows Private Keys live forever, or until someone deletes them.

因此,当PFX导入它们时,它们将永远存在。如果您要导入CurrentUser\My,则这很有意义。

So when the PFX imports them, they live forever. This makes sense if you were importing to CurrentUser\My. It makes less sense if you were doing something transitory.

(大多数情况下)Windows设计是您与证书库交互的,并且从证书库中您可以获得证书。 .NET后来出现了,并且(一个假设是,基于了解应用程序的实际作用)将证书作为顶级对象,并存储了一些次要的东西。

The Windows design is (mostly) that you interact with cert stores, and from cert stores you get certificates. .NET came later, and (one presumes, based on seeing what applications really were doing) made certificates the top-level object, and stores sort of a secondary thing.

因为Windows证书(实际上是存储证书元素)知道其私钥是什么,所以.NET证书知道其私钥是什么。

Because Windows certificates (which are really "store certificate elements") "know" what their private key is, .NET certificates "know" what their private key is.

哦,但是MMC证书管理器说它可以将带有私钥的证书导出到PFX中,为什么证书构造函数除了仅是证书格式之外还不能接受这些字节?好的,现在就可以了。

Oh, but the MMC Certificate Manager says it can export a certificate with its private key (into a PFX), why can't the cert constructor accept those bytes in addition to the "just a cert" format? Okay, so now it can.

您可以打开一些字节作为X509Certificate / X509Certificate2。这是带有无密码的PFX(通过多种可能的正确方式)。您会发现它是错误的,然后让证书转到垃圾收集器。该私钥将永远存在,因此您的硬盘驱动器会慢慢装满,并且密钥存储访问变得越来越慢。然后,您会生气,并重新格式化计算机。

You open some bytes as an X509Certificate/X509Certificate2. It's a PFX with "no password" (via any of the various ways that can be true). You see it's the wrong one, and you let the cert go off to the garbage collector. That private key lives forever, so your hard drive slowly fills up, and key storage access gets slower and slower. Then you get angry, and reformat your computer.

这似乎很糟糕,所以.NET要做的是当(某个字段)证书被垃圾收集时(实际上,最终完成),它告诉CAPI(或CNG)删除密钥。现在事情按预期进行了,对不对?好吧,只要程序不会异常终止。

That seems bad, so what .NET does is when (a field of) a cert is getting garbage collected (actually, finalized) it tells CAPI (or CNG) to delete the key. Now things work as expected, right? Well, so long as the program doesn't abnormally terminate.

哦,您将其添加到持久存储了吗?但是,在新的证书存储实体知道如何找到私钥之后,我将删除私钥。

Oh, you added it to a persisted store? But I'm going to delete the private key after the new certificate store entity "knows" how to find the private key. That seems bad.

PersistKeySet说不要执行删除操作。

PersistKeySet says "don't do that deleting thing". It's for when you intend to add the cert to an X509Store.

如果要在不指定标志的情况下进行相同的操作,请致电 Environment.FailFast ,或在导入后拔掉计算机的电源。

If you want the same behavior without specifying the flag, call Environment.FailFast, or unplug the computer, after doing the import.

在.NET中,您可以轻松地获得集合中的证书,并对其调用导出。如果有些具有机器密钥,而另一些具有用户密钥怎么办? PFXExportCertStore可以解救。导出机器密钥时,它会写下一个标识符,说它是机器密钥,因此导入会将其放回原处。

In .NET you can easily have a grab bag of certs in a collection and call Export on it. What if some have machine keys, and others have user keys? PFXExportCertStore to the rescue. When a machine key is exported it writes down an identifier that says it was a machine key, so import puts it back to the same place.

通常,这很好。也许您从一台机器上导出了机器密钥,而您只是想以非管理员身份检查另一台机器上的机器密钥。好的,您可以指定 CRYPT_USER_KEYSET X509KeyStorageFlags.UserKeySet

Well, usually. Maybe you exported a machine key off of one machine, and you want to just inspect it as a non-admin on another machine. Okay, you can specify CRYPT_USER_KEYSET aka X509KeyStorageFlags.UserKeySet.

哦,您是在一台计算机上以用户身份创建的,但又希望将其作为另一台计算机上的计算机密钥吗?精细。 CRYPT_MACHINE_KEYSET / X509KeyStorageFlags.MachineKeySet

Oh, you created this as a user on one machine, but want it as a machine key on another? Fine. CRYPT_MACHINE_KEYSET / X509KeyStorageFlags.MachineKeySet.

如果您只是检查PFX文件,或者想暂时使用它们,为什么还要在以下位置将密钥写入磁盘所有?好的,Windows Vista说,我们可以直接将私钥加载到加密密钥对象中,然后告诉您指针。

If you're just inspecting PFX files, or otherwise wanting to work with them on a temporary basis, why bother writing the key to disk at all? Okay, says Windows Vista, we can just load the private key directly into a crypto key object, and we'll tell you the pointer.

PKCS12_NO_PERSIST_KEY / X509KeyStorageFlags.EphemeralKeySet

我想想如果Windows有在NT4中,此功能将是.NET的默认功能。它现在不能成为默认值,因为太多的事情取决于正常导入如何检测私钥是否可用的内部原理。

I'd like to think that if Windows had this feature in NT4 that this would have been the default for .NET. It can't be the default now, because too many things depend on the internals of how the "normal" import works to detect if a private key is usable.

PFXImportCertStore的默认模式是私钥不应重新导出。要说明这是错误的,可以指定 CRYPT_EXPORTABLE / X509KeyStorageFlags.Exportable

PFXImportCertStore's default mode is that the private keys should not be re-exportable. To tell it that it's wrong you can specify CRYPT_EXPORTABLE / X509KeyStorageFlags.Exportable.

CAPI和CNG都支持一种机制,在使用私钥之前,软件密钥可能需要征得同意或输入密码(例如智能卡的PIN提示),但是您必须在首次创建时声明(或导入)密钥。因此,PFXImportCertStore允许您指定 CRYPT_USER_PROTECTED (.NET将其公开为 X509KeyStorageFlags.UserProtected )。

CAPI and CNG both support a mechanism where the software keys can require consent or a password before the private key can be used (like a PIN prompt for a smart card), but you have to declare that when first creating (or importing) the key. So PFXImportCertStore allows you to specify CRYPT_USER_PROTECTED (and .NET exposes it as X509KeyStorageFlags.UserProtected).

最后两个实际上仅对一个私钥 PFX有意义,因为它们适用于所有密钥。它们也没有包含原始密钥可能具有的所有选项... CNG和CAPI都支持可存档密钥,这意味着可一次导出。机器密钥上的自定义ACL也不支持PFX。

These last two really only make sense for the "one private key" PFXes, because they apply to all the keys. They also don't encompass the full range of options that the origin keys could have had... both CNG and CAPI support "archivable" keys, which means "exportable once". Custom ACLs on machine keys also don't get any support in PFX.

对于证书(或证书的集合),一切都很容易。一旦涉及到私钥,事情就会变得一团糟,Windows证书(存储)的抽象就会变得稀疏,您需要了解持久性模型和存储模型。

For a certificate (or a collection of certificates), everything's easy. Once the private keys are involved things get messy, and the abstraction over Windows certificate (stores) gets a little thin and you need to be aware of the persistence model and the storage model.

这篇关于所有不同的X509KeyStorageFlags的基本原理是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆