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

proposal: crypto/x509: allow certificates to be exported from CertPool #26614

Closed
btoews opened this issue Jul 26, 2018 · 6 comments
Closed

proposal: crypto/x509: allow certificates to be exported from CertPool #26614

btoews opened this issue Jul 26, 2018 · 6 comments
Labels
FrozenDueToAge Proposal Proposal-Crypto Proposal related to crypto packages or other security issues
Milestone

Comments

@btoews
Copy link

btoews commented Jul 26, 2018

Copied from review 126016 (@FiloSottile asked me to open a proposal issue):

Some users may find it helpful to be able to inspect the Roots/Intermediates in a VerifyOptions.

The main issue with exposing this is that users could mess with the slice, causing the two indices (bySubjectKeyId and byName) to be broken. To avoid this, a Certificates() method is added, returning a copy of the internal slice.

In the review, @FiloSottile said:

We will have to be careful considering this change because we don't want to necessarily require the availability of full certificates on all OSes to support SystemCertPool, as opposed to just the subjects which might be all the system API returns.

I admit, I hadn't looked too carefully into how SystemCertPool was implemented on various systems. My desire for this change is a situation where a certificate from the Intermediates of a VerifyOptions needs to be inspected. In my case, the CertPool is is not going to be the SystemRoots, but something the user has constructed.

Maybe, to support my use case, as well as to support system stores where the actual certs aren't available, the function could be changed to return an error if the certs aren't available. We could check this by seeing if the length of the subject list matches the length of the certs member. Does that sound reasonable?

Edit: Just to decouple this a bit from the premature review I opened, here's the signature I'm suggesting:

func (s *CertPool) Certificates() ([]*Certificate, error)
@meirf
Copy link
Contributor

meirf commented Jul 26, 2018

@mastahyeti I assume by CertStore you meant CertPool. Just in case you meant to define a new type (I don't see CertStore anywhere), please define it a bit.

@btoews
Copy link
Author

btoews commented Jul 26, 2018

Yes. Thanks. I updated the OP.

@FiloSottile FiloSottile added the Proposal-Crypto Proposal related to crypto packages or other security issues label Jul 26, 2018
@adamdecaf
Copy link
Contributor

adamdecaf commented Jul 26, 2018

Is there a use-case for reading all certificates returned? I could see removing certificates from a CertPool at runtime, but it might be easier to whitelist certificates into an empty CertPool.

Would inspecting the chains from a certificate perhaps solve the problem better? There's already a method for this.

func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error)

@btoews
Copy link
Author

btoews commented Jul 26, 2018

I'm starting to think that my use case is outside the intended purpose of this type.

I'm working on a library that creates/verifies CMS (PKCS#7 / S/MIME) SignedData structures. The structure will usually contain all or part of the chains needed to verify its signatures. It's possible though for it to contain no certificates, expecting the verifier to lookup the signing certificate by issuer/SN and build the chain itself. My verification method has a signature like this

func (sd *SignedData) Verify(opts x509.VerifyOptions) (chains [][][]*x509.Certificate, err error)

In the rare case where the SignedData doesn't include the leaf certificate that created the signature, I'd like the caller to be able to provide the leaf certificate as an additional intermediate in the VerifyOptions struct.

While this makes for a convenient API for my library, I'm realizing that I may be abusing the CertPool type by wanting to treat it as an arbitrary collection of certificates instead of just a set of intermediates or roots for chain building.

@btoews btoews closed this as completed Sep 5, 2018
@elagergren-spideroak
Copy link

elagergren-spideroak commented May 20, 2019

I'd like to reopen this issue.

We have, due to business requirements, a drop-in replacement for crypto/tls. The underlying library we use requires its own sort of certificate pool that we have to construct with individual certificates.

Because x509.CertPool does not provide a way to extract a copy of the certificates we have to ignore the (crypto/tls.Config).RootCAs field and load system certificates. In practice this works, but it makes testing particularly troublesome. It also limits what we're able to do with certificates in the future.

I'd like to propose this API:

// Certificates returns a copy of the certificates inside the CertPool, if any.
// The bool indicates the availability of full Certificates.
func (p *CertPool) Certificates() ([]*Certificate, bool)

@flyinprogrammer
Copy link

I tried making a tool today that would try and verify if particular system certificates were present on the host, rather than blow up at runtime. And it's impossible to build that tool without this API change, or cloning most of the code here and building my own library.

Also: https://github.com/golang/go/blob/master/src/crypto/x509/cert_pool.go#L151-L159
is not sufficient because I still don't have a way to actually verify certificate material.

Hopefully no one finds this, but should you happen to try and actually iterate on the Subjects of your CertPool - RawSubject is actually a RDNSequence, not a pkix.Name

for i, rawSubject := range subjects {
	var rdnSequence pkix.RDNSequence
	_, err := asn1.Unmarshal(rawSubject, &rdnSequence)
	if err != nil {
		log.Fatal("could not unmarshal der formatted subject")
	}
	var name pkix.Name
	name.FillFromRDNSequence(&rdnSequence)
	fmt.Printf("cert %d: %s\n", i, name.CommonName)

}

https://play.golang.org/p/Adz1yjfm58_i

dnephin added a commit to hashicorp/consul that referenced this issue Apr 13, 2021
There is no way to compare x509.CertPools now that it has an unexpected
function field. This comparison is as close as we can get.

See golang/go#26614 for a related issue.
@golang golang locked and limited conversation to collaborators Apr 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge Proposal Proposal-Crypto Proposal related to crypto packages or other security issues
Projects
None yet
Development

No branches or pull requests

7 participants