Open aerth opened 4 years ago
A property consists of a data structure that looks like this (taken from the certinject comments):
// 5c 00 00 00 // propid
// 01 00 00 00 // unknown (possibly a version or flags field; value is always the same in my testing)
// 04 00 00 00 // size (little endian)
// subject public key bit length // data[size]
In other words, there's a 32-bit little-endian unsigned "Property ID", a 32-bit little-endian unsigned value that's probably a version field (it's always 0x1), a 32-bit little-endian unsigned size, and then raw data with a size in bytes equal to the value of the size field.
A blob is simply a concatenated sequence of properties.
It would be useful to have a Go struct
for a Property
, which can be marshaled and unmarshaled based on the above serialization. (I don't see any need to allow pathological Properties, i.e. the calculation of the size, and the version field, can be part of the marshal/unmarshal code, not the struct
itself.) It would further be useful to have a Go type
for a Blob
, which could be a map
of Property ID's to their binary values. Preferably the marshal/unmarshal functions for Blob
would sort by Property ID so that it's deterministic.
Also, lists of property ID's are in wincrypt.h and certenroll.h. The latter has more properties; properties that exist in the former appear to exist in Windows XP; properties that exist in the latter appear to exist in Windows Vista.
The values from wincrypt.h
in ReactOS are at https://github.com/reactos/reactos/blob/5542dd50d64ba0712fa3ddca3497b8ac5bcd2949/sdk/include/psdk/wincrypt.h#L2684-L2744 .
The three Property ID's that look immediately interesting to me are:
CERT_ENHKEY_USAGE_PROP_ID
= 9CERT_ROOT_PROGRAM_NAME_CONSTRAINTS_PROP_ID
= 84The first two both take the form of the Value of an Extension (see the crypto/x509/pkix
package). CERT_ENHKEY_USAGE_PROP_ID
is an Extended Key Usage extension; CERT_ROOT_PROGRAM_NAME_CONSTRAINTS_PROP_ID
is a Name Constraints extension. It is not 100% clear whether these properties act as additional constraints on the certificate, or if they replace whatever constraints are already present in the certificate (some testing would be useful here), though I'm guessing it's the former. It's also not clear what happens if the same certificate exists in 2 physical stores but with different values for these properties.
This is a place I am collecting
using certmgr to add a certificate, a ProtectedRoots key is created/updated
With no certificates added, the empty ProtectedRoots is
With a single certificate, the ProtectedRoots key contains
Using syscalls, trusting a certificate creates the same popup as certmgr
Using certinject, it only works with system + Root, and the blob header is different
Here is certinject injected certificate into the current-user + Root store, which doesn't get recognized by the browser like the certinject system+Root or the syscall technique (the one with the popup). I think its because we don't modify the ProtectedRoots, not sure.
Headers (first bytes of the blob)
In each case, the registry blob contains a header containing various sorts of meta data, and then the rest is the DER/ASN.1 certificate bytes.
In the example certificate, the certificate bytes begin with
30 82 03 79
and end withE1 36 3A D5
89
and the SHA-1 is (20 bytes)99 C1...34 97
Here is a list of a few discovered headers:
Added with certinject1:
??? KEY_IDENTIFIER A 20-byte array containing the SHA-1 hash of the certificate subject public key. ??? (works (as administrator)in System+Root, Enterprise+Root)
Added with certmgr:
Info
Certificate as Registry Key
Useful References
CryptoAPI constants
Certificate BLOB Properties
Common Windows Structures
[MS-CRTD]: Certificate Templates Structure
Microsoft Certificate Encoding
Typical Encoded Certificate from Vista
Certificate Properties
Example Certificate
The example self-signed certificate is the one found here: https://selfsigned.badssl.com/
It expires on Friday, October 8, 2021 at 11:41:52 PM.
SHA-1 Fingerprint (unfortunately used all over the place, still.)
SHA-256 Fingerprint:
Since we don't control this certificate, at some point it will expire and we will have to patch this test.