namecoin / certinject

Inject certificates into Windows CryptoAPI trust store, with EKU and name constraints.
https://www.namecoin.org/
GNU General Public License v3.0
2 stars 5 forks source link

encoding and decoding certificate blobs #12

Open aerth opened 4 years ago

aerth commented 4 years ago

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

18 00 00 00 01 00 00 00
90 85 C3 79 A5 43 D6 01
00 00 00 00 18 00 00 00

With a single certificate, the ProtectedRoots key contains

18 00 00 00 01 00 00 00
30 20 40 BE 95 43 D6 01
01 00 00 00 18 00 00 00
[ 20 BYTE SHA-1 HASH ]

image

Using syscalls, trusting a certificate creates the same popup as certmgr

image

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.

image

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 with E1 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)

20 00 00 00 01 00 00 00
7d 03 00 00

Added with certmgr:

30 00 00 00 01 00 00 00
14 00 00 00 .. [ 20 byte sha-1 hash ]
...
5c 00 00 00 01 00 00 00
04 00 00 00 00 80 00 00

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.)

99 C1 DA F0 7C 8D 69 A8 A0 65 49 2D CA AE 43 C4 3F F1 34 97

SHA-256 Fingerprint:

1D E4 07 4B 4E 38 37 7F 43 67 30 3F 4A 19 C9 86 A5 06 18 0F 22 A6 E5 3A 68 CC 76 79 EA 6D 9C 74

Since we don't control this certificate, at some point it will expire and we will have to patch this test.

JeremyRand commented 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.

JeremyRand commented 4 years ago

The values from wincrypt.h in ReactOS are at https://github.com/reactos/reactos/blob/5542dd50d64ba0712fa3ddca3497b8ac5bcd2949/sdk/include/psdk/wincrypt.h#L2684-L2744 .

JeremyRand commented 4 years ago

The three Property ID's that look immediately interesting to me are:

The 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.