Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raw data in x509.Certificate does not equal RawLogEntry.Cert.Data for precertificates #950

Open
d-Rickyy-b opened this issue Jun 20, 2022 · 2 comments

Comments

@d-Rickyy-b
Copy link

Hi there,

this is a follow-up to #947.

Description

I want to generate hashes of certificates. To do that I use the raw data (bytes) stored in x509.Certificate.Raw. For x509.Certificate generated from Precertificate entries I am not getting the full (raw) certificate data in the x509.Certificate.Raw field.

Going one layer up, the Precertificate field Submitted contains the full submitted data which is also what I expected to be contained within the x509.Certificate.Raw field. Instead the Raw field seems to contain the unsigned certificate, which I don't fully understand. Eventually, for the TBS cert there is a whole other field (RawTBSCertificate). Also the Signature field is empty for Precertificates.

Looking at the Precertificate docs for the field Submitted:

// DER-encoded pre-certificate as originally added, which includes [...] a signature generated over the pre-cert by the pre-cert issuer (which might differ from the issuer of the final cert, see RFC6962 s3.1).

Regular entry:

grafik
The ct.RawLogEntry.Cert.Data does equal the LogEntry.

Precertificate entry:

grafik

Question

Is it intended that Precertificates do not contain the full DER-encoded data including the generated signature in the Raw field, but instead we must fall back to the Precertificate.Submitted field? I thought it would be more consistent and easier to have the raw certificate data in one place and not multiple ones.

@AlCutter
Copy link
Member

AlCutter commented Jul 5, 2022

Hi Ricky,

I think the field in Precertificate called TBSCertificate is the one you're talking about, right?

If so, as the comment on that field says, it's really just a convenience thing to have have easy access to the fields in the TBS from the precert.

One thing to bear in mind is that the TBS cert will have been modified from the form it was in when it was read from the precert (see here for the processing that happens). At this point the original signature from the precert is not going to be valid for the marshalled TBS DER bytes, and unmarshalling the original precert DER bytes wouldn't recreate the TBS structure, so putting those precert DER bytes into the TBSCertificate.Raw field would be rather more confusing.

It could be argued that Precertificate.Submitted should have been called Precertificate.Raw though, but that's another story :)

Hope that's helpful.

Cheers,
Al.

@d-Rickyy-b
Copy link
Author

Hi there,

I think the field in Precertificate called TBSCertificate is the one you're talking about, right?

Yes

If so, as the comment on that field says, it's really just a convenience thing to have have easy access to the fields in the TBS from the precert.

Okay, I understand that.

[...] so putting those precert DER bytes into the TBSCertificate.Raw field would be rather more confusing.

But currently TBSCertificate.Raw seems to be the same as TBSCertificate.RawTBSCertificate? This is intended? I mean it says that Raw is the "Complete ASN.1 DER content". I still don't get how it is the exact same as the RawTBSCertificate.

Maybe I can try to explain my use case. Currently I'm doing something like this:

var rawLogEntry *ct.RawLogEntry
// [...]
logEntry, _ := rawLogEntry.ToLogEntry()

var cert *x509.Certificate
var rawData []byte
switch {
	case logEntry.X509Cert != nil:
		cert = logEntry.X509Cert
		rawData = logEntry.X509Cert.Raw
	case logEntry.Precert != nil:
		cert = logEntry.Precert.TBSCertificate
		rawData = logEntry.Precert.Submitted.Data
	default:
		log.Println("Could not find certificate in entry")
	}

calculatedHash := calculateSHA1(rawData)

I want to extract the raw bytes and the parsed certificate information for both, regular certs and precerts.
It feels very unintuitive for me to have two separate case statements which try to retrieve the same information (cert + raw bytes) about both variants from different places. I would have wished for a more uniform way to retrieve the raw bytes such as:

switch {
	case logEntry.X509Cert != nil:
		cert = logEntry.X509Cert
		rawData = logEntry.X509Cert.Raw
	case logEntry.Precert != nil:
		cert = logEntry.Precert  // or logEntry.Precert.TBSCertificate, 
		rawData = logEntry.Precert.Raw
	default:
		log.Println("Could not find certificate in entry")
	}

If everything works as intended, feel free to close this issue or keep it as a mere suggestion. It just feels weird so I wanted to ask if I was doing something wrong or if this is the way the code is supposed to work.

Cheers,
Rico

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants