--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
GitHub Issues: https://github.com/hashicorp/vault/issues
IRC: #vault-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Vault" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vault-tool+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vault-tool/54773c5d-789d-488b-8209-8d223593cc36%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
To unsubscribe from this group and stop receiving emails from it, send an email to vault-tool+...@googlegroups.com.
To unsubscribe from this group and stop receiving emails from it, send an email to vault-tool+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vault-tool/61bdca98-1435-4ac7-bbfa-9eaadc946a49%40googlegroups.com.
Unfortunately, I'm not sure this is working. Or... specifically, I'm not sure the output of this is working. I created two roots in vault (A and B), used sign-self-issued to sign B by A, and then tried to validate B using a bundle of just A.
Self-issued certificates are CA certificates in which the issuer and subject are the same entity. Self-issued certificates are generated to support changes in policy or operations. Self- signed certificates are self-issued certificates where the digital signature may be verified by the public key bound into the certificate.
The go standard library gives you NameMistmatch error "issuer name does not match subject from issuing certificate". OpenSSL gives me a "unable to get local issuer certificate" error. Just to be even more fun, golang is happy with the self-issued-but-signed-by-other when added as a root, but openssl is not. I think in the openssl case, it's not able to find the certificate since it's looking it up by issuer string (version 0.9.8hz on OSX). I think golang finds parents by keys but then validates by issuer and subject names.
I'll admit that I'm used to the issuer being the definitive key to look up for name, but the go library is obviously a little different even if it uses the issuer as the final determination of validity of the chain.Unfortunately, I can't say which way is right... I can't find a useful standard for this behavior at all. Found the ITU standard on the certificate, but I'm not seeing anything about how to handle use cases like this....
So what this endpoint does is exactly what it says -- it signs a self-issued certificate. The RFC is quite clear what a self-issued certificate is; it's a certificate which has the same Issuer and Subject DNs:Self-issued certificates are CA certificates in which the issuer and subject are the same entity. Self-issued certificates are generated to support changes in policy or operations. Self- signed certificates are self-issued certificates where the digital signature may be verified by the public key bound into the certificate.The endpoint takes a self-issued certificate and signs it; the output therefore is a certificate that is self-issued but where the digital signature is verified not by the public key bound into the certificate, but by a different key, encoded in the authority key identifier. So it's self-issued but not self-signed.Now, it's possible that it turns out that this is not actually what you *want*. :-) But as far as I can tell, the endpoint does what it claims to do, and as far as I can tell it's a *valid* thing to do. You're using the digital signature of something you trust to assert that the self-issued certificate is valid, which helps bootstrap a new root. The rest is just verification logic. But speaking of that...
To meet this goal, the path validation process verifies, among other
things, that a prospective certification path (a sequence of n
certificates) satisfies the following conditions:
(a) for all x in {1, ..., n-1}, the subject of certificate x is
the issuer of certificate x+1;The go standard library gives you NameMistmatch error "issuer name does not match subject from issuing certificate". OpenSSL gives me a "unable to get local issuer certificate" error. Just to be even more fun, golang is happy with the self-issued-but-signed-by-other when added as a root, but openssl is not. I think in the openssl case, it's not able to find the certificate since it's looking it up by issuer string (version 0.9.8hz on OSX). I think golang finds parents by keys but then validates by issuer and subject names.One thing I've found over the last couple of years -- and you can see this in the history of the PKI backend between the 0.3 and 0.6 releases especially as we got feedback from users on various other crypto stacks -- is that it's one thing for the RFC to say something is valid and quite another for the various crypto stacks to *like* it. For instance, we used to by default sign certificates with the Any usage so that, in absence of specific usage information, they could be used for any purpose, only to find that some crypto stacks (IIRC Mozilla's) just say "nope" to Any. There's actually a comment in the Golang code around how some of its behavior was modeled after the Windows Crypto API -- for better and for worse.
I'll admit that I'm used to the issuer being the definitive key to look up for name, but the go library is obviously a little different even if it uses the issuer as the final determination of validity of the chain.Unfortunately, I can't say which way is right... I can't find a useful standard for this behavior at all. Found the ITU standard on the certificate, but I'm not seeing anything about how to handle use cases like this....I can't either. I'm happy to change the endpoint logic to do the right thing if the right thing is something other than what it's doing. (I'm also happy to leave it alone for the few but valid use-cases it provides, and add another endpoint to do something that fits your use-case.)What I don't really know however is what will work for your use-case if this doesn't. I fully admit this isn't common. Even the Let's Encrypt certs that were signed by a third party CA to get them bootstrapped weren't actually self-issued certs. Mimicking this kind of signing can already be done via the intermediate (sign-intermediate/set-signed) endpoints, because there the subject can be what you provide but the issuer will be the root CA; the point of the new endpoint was to go a step further and also deal with real, honest-to-goodness self-issued certs. And if you want to bootstrap a new root CA cert, if anything else is the issuer it's not really a root, is it.
I'm all ears in terms of what you think will actually solve your use-case, but my current understanding is that in theory this should have done it, and it's RFC-valid, except in practice in the real world you're finding that the crypto stacks are like "meh, nah" in their validation code.
Let me know if you have any advice. I'm versed in X509 but not an expert, and perhaps someone will know what, if anything, I'm doing wrong here.
I think the crux is producing certificates which can be used in as part of a valid chain, and this hinges on the issuer/subject match. In RFC5280,Section 6:To meet this goal, the path validation process verifies, among otherthings, that a prospective certification path (a sequence of n certificates) satisfies the following conditions: (a) for all x in {1, ..., n-1}, the subject of certificate x is the issuer of certificate x+1;
trust anchor information, describing a CA that serves as a
trust anchor for the certification path. The trust anchor
information includes:
(1) the trusted issuer name,
(2) the trusted public key algorithm,
(3) the trusted public key, and
(4) optionally, the trusted public key parameters associated
with the public key.
The trust anchor information may be provided to the path
processing procedure in the form of a self-signed certificate.
When the trust anchor information is provided in the form of a
certificate, the name in the subject field is used as the trusted
issuer name and the contents of the subjectPublicKeyInfo field is
used as the source of the trusted public key algorithm and the
trusted public key.The primary goal of path validation is to verify the binding between a subject distinguished name or a subject alternative name and subject public key, as represented in the target certificate, based on the public key of the trust anchor.
To meet this goal, the path validation process verifies, among other
things, that a prospective certification path (a sequence of n
certificates) satisfies the following conditions:
(a) for all x in {1, ..., n-1}, the subject of certificate x is
the issuer of certificate x+1;
(b) certificate 1 is issued by the trust anchor;
(c) certificate n is the certificate to be validated (i.e., the
target certificate); and
(d) for all x in {1, ..., n}, the certificate was valid at the
time in question.A certificate is self-issued if the same DN appears in the subject and issuer fields (the two DNs are the same if they match according to the rules specified in Section 7.1). In general, the issuer and subject of the certificates that make up a path are different for each certificate. However, a CA may issue a certificate to itself to support key rollover or changes in certificate policies. These self-issued certificates are not counted when evaluating path length or name constraints.
I've been issuing generations of the "root" certificates with the generations having different generation names (ala G1, G2, G3...), and the Gn generation being issued by the G(n-1) generation. This is valid - outside of the questionable constraint of not issuing a certificate which expires after the issuing certificate (see prior openssl reference).
This makes the only valid(?) use of a self-issued certificate is when it is also signed by a certificate which has the same subject. But the sign-self-issued endpoint does still allow for the new cert's issuer/subject to differ from the current subject.
Off the cuff, do you know of a library that doesn't enforce the issuer<->parent subject naming check?
For my use case, I've been using the generational "root" certificates. I'll admit that this a constraint that I'm going on based on other descriptions (e.g. Docker's cert rotation: https://docs.docker.com/engine/swarm/how-swarm-mode-works/pki/) but the description is never precise and I can't say if that implementation is exactly that way or not (I'll take a look at the code after some sleep). To that end, for my use case it might match more to creating a new endpoint - issue-ignoretime or something probably better named - which will sign certs without looking at the time window on them..
The crypto libraries are unhappy because, in the generational model, there's a difference between the issuer on the second cert and the subject of the issuing cert (based on KeyID). If the issuer/subject of the "new" root matches the subject of the old "root", both openssl and golang verify it successfully.
(k) max_path_length: this integer is initialized to n, is
decremented for each non-self-issued certificate in the path,
and may be reduced to the value in the path length constraint
field within the basic constraints extension of a CA
certificate."For each non-self-issued certificate". Which suggests that you can have multiple self-issued certificates in a chain, which again, means the Issuer/Subject DNs match, and if the key is the same as the subject it's self-signed, which denotes a root, so you wouldn't have more than one of those in the path. So the RFC here is suggesting that sure, you can totally have self-issued certs in a path (which would be anchored by a trust anchor, which is maybe a self-signed cert but not required and really is a trusted public key). You can see why I thought the way it was implemented was the right thing to do...
So while option 2 is also possible, it probably means that you would want to ensure that your root has no path length constraint, and if your want to go gen1 -> gen2 -> gen3 -> etc. you'd never want to introduce a path length constraint because eventually you'll run out. And, oh, that pesky thing about statement (d) in the algorithm, except openssl ignores and other crypto stacks may or may not ignore.
And of course, option 1, if the Subject/Issuer DNs aren't the same, also potentially has path length concerns.
Oh, X509.
Let me know your thoughts...
Best,
Jeff
My concerns about step (d) in the path validation is literally, when a certificate in the chain is expired, which is how I originally read the openssl issue, that it would ignore an *expired* certificate.However, the openssl issue is actually saying that it doesn't validate that the *range* of validity. If you have a CA cert that expires after its root, openssl is fine with that -- and that's as it should be. What the issue doesn't say is that openssl doesn't check validity of each cert in its path against the *current* time.
So please read the above post with that in mind -- I had thought from my initial reading that it was saying openssl is fine with expired certs, but it's actually just saying that openssl doesn't pre-judge certificates based on validity period, so long as they are valid now. Which makes sense.Assuming openssl in fact does do part (d) of that algorithm properly, it does make me think that it's still a bad idea to issue a certificate valid past the parent's expiration, because unless I'm misreading the RFC it seems like that should, in fact, cause validation to fail. (See my note in the previous email about my experience with true self-signed root CAs on the public internet being that their validity is in decades, which gives plenty of time to create a new root, get it into browsers, and switch over issuance of certs way in advance of expiration.)
That makes me think option 2 is maybe not a bad idea, but a useless one and leads me back to option 1.If you really truly want a new root, I think you need to create a new root. You could cross-sign it to make it palatable to applications while you seed the new root around, so I think in that case the sign-self-issued still makes sense, but with the ability to set the Issuer as expected (maybe toggleable with the current behavior for those using custom validation logic).
I could also maybe add the ability to issue a new self-signed cert with the same key you're already using -- again, depends on how you want to define trust anchor and your validation logic -- but I think in most cases you'd still have to seed this cert around because if you're not going solely on public key you still need a mapping to a real cert (and if this wasn't the case the endpoint would be acceptable as-is). So I think this puts you in the same boat as getting a new real root, except that you aren't also rotating your key...so generally a loss, not a win.In your generation-based example, you didn't go into any details about validity, but you did say you've been doing that up to this point. I'm curious about whether you have hit a point where any of the certificates were actually past their validity date and the behavior of crypto stacks if so.
I think the crux is producing certificates which can be used in as part of a valid chain, and this hinges on the issuer/subject match. In RFC5280,Section 6:To meet this goal, the path validation process verifies, among otherthings, that a prospective certification path (a sequence of n certificates) satisfies the following conditions: (a) for all x in {1, ..., n-1}, the subject of certificate x is the issuer of certificate x+1;The context before and after this snippet is relevant. But first, we have to note what defines a trust anchor:
(1) the trusted issuer name,
The trust anchor information may be provided to the path processing procedure in the form of a self-signed certificate. When the trust anchor information is provided in the form of a certificate, the name in the subject field is used as the trusted issuer name and the contents of the subjectPublicKeyInfo field is used as the source of the trusted public key algorithm and the trusted public key.You'll probably note something important here, which is that a trust anchor *may* be provided as a self-signed certificate. But it's not a requirement; essentially the trust anchor is defining a trusted public key.
Moving down, we see:The primary goal of path validation is to verify the binding between a subject distinguished name or a subject alternative name and subject public key, as represented in the target certificate, based on the public key of the trust anchor.Here's that annoying thing again -- the goal is to verify the binding _based on the public key of the trust anchor_, which as we found before isn't required to be in the form of a self-signed certificate. But you can imagine that you could have a trusted root defining a trusted public key, and the public key itself satisfying the requirements of the trust anchor.
(a) for all x in {1, ..., n-1}, the subject of certificate x isthe issuer of certificate x+1; (b) certificate 1 is issued by the trust anchor; (c) certificate n is the certificate to be validated (i.e., the target certificate); and (d) for all x in {1, ..., n}, the certificate was valid at the time in question.You quoted (a) before, but (b) and (d) are both super important. (b) says certificate 1 is issued by the trust anchor, but it doesn't specify whether issued here means that the Issuer DN encoded in the certificate must match that of a self-signed certificate signing the public key of the trust anchor (which as we found earlier is not a requirement for trusting a public key). So in theory, a certificate with a signature from the right public key and authority key id encoded in the cert ought to be satisfied by the "issued by the trust anchor" line.
The issuer field identifies the entity who has signed and issued the certificate. The issuer field MUST contain a non-empty distinguished name (DN).
This extension is used where an issuer has multiple signing keys (either due to multiple concurrent key pairs or due to changeover).
(d) is obviously relevant here because it means that if you're walking up a certification path, you can't have a certificate issued that is not a root in a certification path be valid while the issuer isn't. We'll get back to that, but we have to look at one more thing first, which is just below the path validation algorithm:A certificate is self-issued if the same DN appears in the subject and issuer fields (the two DNs are the same if they match according to the rules specified in Section 7.1). In general, the issuer and subject of the certificates that make up a path are different for each certificate. However, a CA may issue a certificate to itself to support key rollover or changes in certificate policies. These self-issued certificates are not counted when evaluating path length or name constraints.Here's where we get into trouble.This explicitly says that a CA may issue a certificate to itself to support key rollover, and these self-issued certificates are not counted when evaluating name constraints. The "name constraints" here likely means not the DNs, but rather the permitted DNS domains on a cert. Likely. Maybe. I think. But regardless, this paragraph was the kicker for me thinking that the right thing to do was to code it as I did.The reason is that if you need to support key rollover, it can't be a self-signed cert. If it was, you wouldn't be rolling over to a new key, you'd be using the same one -- issuing a self-issued cert with the same key (e.g. self-signed) would roll over nothing.
It's actually not super clear what the right thing is, and that's the problem, and it's why different crypto stacks behave in different ways based on interpretation. This goes back to my statement of thinking that what the endpoint does is literally a valid thing to do, but it also means other people have to be willing to validate it that way. :-(So here we're at a point where based on the definition of a trust anchor and based on the explicit text of self-issued certs being used for key rollover...well...
OK, so let's get to what you've been doing:I've been issuing generations of the "root" certificates with the generations having different generation names (ala G1, G2, G3...), and the Gn generation being issued by the G(n-1) generation. This is valid - outside of the questionable constraint of not issuing a certificate which expires after the issuing certificate (see prior openssl reference).Right, so going back to (d) in the path verification algorithm, this should be invalid. I realize the openssl person said there's no requirement for the CA higher up the chain to be valid, but that probably depends on whether you are following the given path validation logic in the RFC to the letter, because (d) seems to indicate that this should in fact be invalid once the root CA expires, since if the trust anchor is a self-signed certificate, that puts it in the validation chain (the text only says that path length and name constraints checks are skipped for self-issued certs).
This makes the only valid(?) use of a self-issued certificate is when it is also signed by a certificate which has the same subject. But the sign-self-issued endpoint does still allow for the new cert's issuer/subject to differ from the current subject.It does? I have checks in there that should ensure it doesn't, and a unit test besides. Or did you assume this?
Off the cuff, do you know of a library that doesn't enforce the issuer<->parent subject naming check?No, but off the cuff I don't know the details of how various crypto stacks have coded their validation algorithms :-)
For my use case, I've been using the generational "root" certificates. I'll admit that this a constraint that I'm going on based on other descriptions (e.g. Docker's cert rotation: https://docs.docker.com/engine/swarm/how-swarm-mode-works/pki/) but the description is never precise and I can't say if that implementation is exactly that way or not (I'll take a look at the code after some sleep). To that end, for my use case it might match more to creating a new endpoint - issue-ignoretime or something probably better named - which will sign certs without looking at the time window on them..Their cert rotation indicates that they just issue a new root and use it as an intermediate until such a time as all of the nodes start using certs issued by that CA. As you said, the details are scarce. If you dig into the code I'd be interested in knowing what they're doing (I may give it a try later but can't at the moment), because it seems like the same problem -- if your new "root" cert is issued by your old root cert, and isn't self-signed, then if clients don't have the old root cert for path validation you should run into a problem. Unless all of the clients carry around all of the previous roots for path validation, and it only "forgets" the root CA to not ever issue more certs from it. And in fact as you note:The crypto libraries are unhappy because, in the generational model, there's a difference between the issuer on the second cert and the subject of the issuing cert (based on KeyID). If the issuer/subject of the "new" root matches the subject of the old "root", both openssl and golang verify it successfully.Which makes me wonder if there's some custom validation logic they're doing.OK, so I can think of a couple of possibilities. They're not necessarily mutually exclusive. Note that we're going to spin a new release soon and this has only been out in 0.8.2 so I'm happy to switch things up and get a fix for this in as well depending on timing.One possibility would be to put a flag into sign-self-issued that controls whether or not the Issuer uses the CA's issuer DN or the original cert's. If the flag is on this makes it a kind of a "super sign-verbatim" but with a really key difference: because it takes in a cert, not a CSR signed with the private key of the requestor, it means for generating new root certs with the same key you don't need to have access to the CA's private key -- obviously a good thing. *But* if the whole point here is to get a new self-signed root CA with the same key, might as well just not require the certificate to be provided anyways, since the CA knows it, and just provide a desired validity length and a generation number. That wouldn't have the flexibility of using a CSR to specify a custom DN for the new cert, but again, no private key for the CA needed to be exported to generate one. But, a key point here is it doesn't allow for key rotation.So option 1: rather than sign a self-issued cert, just generate a new cert (but not self-issued/self-signed!) with the same key, different DN, and new validity period. (I would think this would fall afoul of (d) above if the original cert expires, and create an ever-longer validation path, but openssl clearly doesn't care about validity period.) Also, allow such a cert with the CA's key and the existing CA as the issuer to be uploaded and replace the cert used for that mount.The option above, if various crypto libraries are happy validating it, is a decent option if you don't want key rotation but just don't want validity to be forever, since it doesn't require knowledge of the private key, and your crypto libraries don't actually care about validity periods when verifying CAs in a validation path.But, what if you do want key rotation?Option 2: allow the sign-intermediate endpoint to use a validity period longer than the original CA. Same concerns with respect to (d) but again, if crypto stacks are happy with this, who am I to judge. (I will also note that in orgs where I've worked and in most public CAs the root CAs have lifetimes counted in decades so nobody on the public internet really has to deal with this much.) But, then I have concerns around path length. From the RFC:(k) max_path_length: this integer is initialized to n, is decremented for each non-self-issued certificate in the path, and may be reduced to the value in the path length constraint field within the basic constraints extension of a CA certificate."For each non-self-issued certificate". Which suggests that you can have multiple self-issued certificates in a chain, which again, means the Issuer/Subject DNs match, and if the key is the same as the subject it's self-signed, which denotes a root, so you wouldn't have more than one of those in the path. So the RFC here is suggesting that sure, you can totally have self-issued certs in a path (which would be anchored by a trust anchor, which is maybe a self-signed cert but not required and really is a trusted public key). You can see why I thought the way it was implemented was the right thing to do...So while option 2 is also possible, it probably means that you would want to ensure that your root has no path length constraint, and if your want to go gen1 -> gen2 -> gen3 -> etc. you'd never want to introduce a path length constraint because eventually you'll run out. And, oh, that pesky thing about statement (d) in the algorithm, except openssl ignores and other crypto stacks may or may not ignore.And of course, option 1, if the Subject/Issuer DNs aren't the same, also potentially has path length concerns.
On Saturday, September 9, 2017 at 7:40:09 AM UTC-7, Jeff Mitchell wrote:My concerns about step (d) in the path validation is literally, when a certificate in the chain is expired, which is how I originally read the openssl issue, that it would ignore an *expired* certificate.However, the openssl issue is actually saying that it doesn't validate that the *range* of validity. If you have a CA cert that expires after its root, openssl is fine with that -- and that's as it should be. What the issue doesn't say is that openssl doesn't check validity of each cert in its path against the *current* time.Odd - when I read that issue, I read it as for signing new certificates, not for validating them (mainly because that was my mental focus at the time... yeah, confirmation bias). I'll admit that I'm not following the use case now. If it's for validating, I feel like I gotta disagree with the issue now ironically, because yeah, that does explicitly go against (d) in the path validation requirement.
This is working in the Golang library - while the original trust anchor certificate is valid. I'll get back two chains, [leaf Intermediate TA2 TA1] and [leaf intermediate TA2], with TA1 and TA2 in the RootPool. I'll get back one chain, [leaf intermediate TA2 TA1] with just TA1 in the RootPool. After TA1 expires, I get [leaf intermediate TA2] even with TA1 in the RootPool.
The trust anchor is basically what goes into your CA bundle. You're right - it doesn't have to be self issued or self signed. I was hoping to find one in the default for OSX or a linux (I could have sworn I saw it before when troubleshooting an intermediate mismatch issue), but I'm not finding any right now. However, in our private CA bundles, the only issue I've seen with non-si and non-ss is that openssl needs to the -partial_chain option for the verify subcommand (can't say if it's needed outside of the verify command...) to not require that the trust anchor of the candidate chain to be si/ss - and prior to 1.0.2g that option is not there. Golang doesn't have that requirement.
You quoted (a) before, but (b) and (d) are both super important. (b) says certificate 1 is issued by the trust anchor, but it doesn't specify whether issued here means that the Issuer DN encoded in the certificate must match that of a self-signed certificate signing the public key of the trust anchor (which as we found earlier is not a requirement for trusting a public key). So in theory, a certificate with a signature from the right public key and authority key id encoded in the cert ought to be satisfied by the "issued by the trust anchor" line.Ok - so, yeah, the big item is "what does issued by mean?"
Reading RFC3820 again, I think 4.1.2.4 locks that one in:The issuer field identifies the entity who has signed and issued the certificate. The issuer field MUST contain a non-empty distinguished name (DN).So, even in the case of having a Authority Key ID, the issuer still has to match a subject field. This kinda makes the situation of self-signed and self-issued to be one and the same at least with respect to the Issuer DN.
Clarifying the Authority Key ID (4.2.1.1):This extension is used where an issuer has multiple signing keys (either due to multiple concurrent key pairs or due to changeover).So, it's not so much to allow for endorsing a certificate without "issuing" it, but for allowing a CA to distinguish between multiple signing keys/certs all of which have the same Subject DN.
In the event of just a key rollover, yes, it would not be a self-signed cert, but it would be self-issued and signed with the original which has a matching subject DN. The original cert (assuming it was set as a root) would have just the Subject Key Identifier. The second cert would have the Authority Key Identifier pointing to the SKI of the original cert, it's own SKI pointing to itself, and the Subject DN and Issuer DN would be the same and matching the Subject DN of the original cert.I think it's coming down to --- issuers are strictly based on the DN.
See use case with the TA1 and TA2 above. The driver behind what I'm doing is trying to keep everything working while doing a "root" (I'm just going to keep saying TA at this point) roll. So, before TA1 expires, I issue TA2 and start issuing certs that chain up to that. Anyone with only TA1 in their CA bundle will trust the new chains because they can draw from TA2->TA1; anyone with both TA1 and TA2 in their bundle are just find an dandy either way because it has two valid cert chains it can try. I have until TA1 expires to make sure that everyone is rolled (at least, every leaf node has the updated TA1+TA2 bundle --- but since the leafs shouldn't outlive their CA, they get rolled as well). I.e. at any given point, no one is expected to trust a cert that's outside the validity window.
Attached is the sample that I used:* original-root : in vault 0.8.2 just generated with original/root/generate/internal* new-root-submitted-to-sign-self-signed: in vault 0.8.2 just generated with new/root/generate/internal* new-root-signed-with-original-via-sign-self-signed : in vault 0.8.2 generated via submitting "new-root-submitted-to-sign-self-signed" to original/root/sign-self-issued (sorry - term mismatch when I originally ran it)In this case, it was just fine signing "CN=new one" with "CN=sample" (original).
I think we're trying to account for a variety of use cases which we haven't codified yet. I'm currently seeing 4 practices:1.) Reissuing an existing CA for key rotation or for policy change: I believe this should behave (minus any potential issue with not matching DNs) as the sign-self-issued is currently. I'm mixed on to if this should allow for certs past their original expiration.
2.) Issuing a rolling chain (my use case). Issuing multiple generations of certificates each of which is built off of the previous generation, but allowed to live longer with the expectation that they will eventually be a ubiquitously shared trust authority and this one will expire out. This is along the lines of the super sign-verbatim.
3.) Cross issuing --- honestly, I'm not sure on this case. I know it's done, but it really seems like an interim step because at some point you have to tell everyone to switch over their intermediate chain. Either way, not sure if there's anything for vault to do for this case -- outside of lifetime.
4.) Just generating new roots with no connection to the old roots other than some partial matching (nothing checked) of the DNs -- and the expectation of having enough time to get root ubiquity for the new roots. Nothing for vault to do special in this case.I believe #1 and #4 are primary for what public CA do. #3 has definitely been used by public CAs (Let's Encrypt being the poster child). #2 is what I did and that was based off of what is in the docker swarm setup and I *believe* what the Windows Internal CA does (I'm going based off colleague's explanation of behavior --- haven't looked at it myself). So, of these, #2 is really used just for private CAs... I think?Does that seem like coverage?
The trust anchor is basically what goes into your CA bundle. You're right - it doesn't have to be self issued or self signed. I was hoping to find one in the default for OSX or a linux (I could have sworn I saw it before when troubleshooting an intermediate mismatch issue), but I'm not finding any right now. However, in our private CA bundles, the only issue I've seen with non-si and non-ss is that openssl needs to the -partial_chain option for the verify subcommand (can't say if it's needed outside of the verify command...) to not require that the trust anchor of the candidate chain to be si/ss - and prior to 1.0.2g that option is not there. Golang doesn't have that requirement.So if I understand what you're saying here, Go doesn't care if the issuer of your CA cert at the root of your available chain is self-signed/issued so long as Go is told that the CA cert is specifically seeded into your root pool (e.g. RootCAs in a tls.Config).
Clarifying the Authority Key ID (4.2.1.1):This extension is used where an issuer has multiple signing keys (either due to multiple concurrent key pairs or due to changeover).So, it's not so much to allow for endorsing a certificate without "issuing" it, but for allowing a CA to distinguish between multiple signing keys/certs all of which have the same Subject DN.But wait! If they all have the same Subject DN, and if they have the same issuer but have "multiple concurrent key pairs", don't you have the exact scenario that sign-self-issued creates? Where it's the same exact entity and the same CA but they may be signed by different keys? :-D
In the event of just a key rollover, yes, it would not be a self-signed cert, but it would be self-issued and signed with the original which has a matching subject DN. The original cert (assuming it was set as a root) would have just the Subject Key Identifier. The second cert would have the Authority Key Identifier pointing to the SKI of the original cert, it's own SKI pointing to itself, and the Subject DN and Issuer DN would be the same and matching the Subject DN of the original cert.I think it's coming down to --- issuers are strictly based on the DN.Agreed...I still think this isn't strictly mandated by the RFC, but the fact that I'm not sure after all this suggests that the spec is not clearly written (what?!?) and anyways, what really matters in the end is what stacks are willing to validate.
Attached is the sample that I used:* original-root : in vault 0.8.2 just generated with original/root/generate/internal* new-root-submitted-to-sign-self-signed: in vault 0.8.2 just generated with new/root/generate/internal* new-root-signed-with-original-via-sign-self-signed : in vault 0.8.2 generated via submitting "new-root-submitted-to-sign-self-signed" to original/root/sign-self-issued (sorry - term mismatch when I originally ran it)In this case, it was just fine signing "CN=new one" with "CN=sample" (original).Ah, no -- remember, what that endpoint does is sign a *self-issued* certificate. What it checks is that the DN and Subject of the certificate *to be signed* are the same. It doesn't matter if there's a match with the signing cert. In your case, since you submitted a self-signed certificate for signing, they matched.
I think we're trying to account for a variety of use cases which we haven't codified yet. I'm currently seeing 4 practices:1.) Reissuing an existing CA for key rotation or for policy change: I believe this should behave (minus any potential issue with not matching DNs) as the sign-self-issued is currently. I'm mixed on to if this should allow for certs past their original expiration.Hang a moment -- if you're reissuing an existing CA for key rotation or policy change this actually doesn't help as-is. Because unless you're reissuing for the *same key* then there will be a difference in the signer vs the encoded subject key id which is what was causing issues for you.Now you *could* use this endpoint to issue new certificates for the same CA *with the same key* by presenting your existing self-signed certificate with that key. But that won't account for policy change (currently). So that puts the usefulness of the whole thing into question.
2.) Issuing a rolling chain (my use case). Issuing multiple generations of certificates each of which is built off of the previous generation, but allowed to live longer with the expectation that they will eventually be a ubiquitously shared trust authority and this one will expire out. This is along the lines of the super sign-verbatim.This makes sense, and allowing it to be issued for longer also makes sense if you are doing partial validation. Two thoughts:* In this case it probably makes sense to generate the new one as an intermediate and then get it signed. What I'm not sure about is whether it should be its own endpoint or not. The existing endpoint is essentially designed for the admin to have a lot of flexibility over the csr they're signing, but you can of course use use_csr_values. So for your use case it seems like you really do just need to use that endpoint but have the restriction on NotAfter ignored if the requested TTL is higher.* On the other hand, if all you really want is to just sign exactly what you're given, including the lifetime, you could issue the cert you want and then ask it to be signed -- exactly what the sign-self-issued endpoint does, but with adjusting the Issuer DN.
4.) Just generating new roots with no connection to the old roots other than some partial matching (nothing checked) of the DNs -- and the expectation of having enough time to get root ubiquity for the new roots. Nothing for vault to do special in this case.I believe #1 and #4 are primary for what public CA do. #3 has definitely been used by public CAs (Let's Encrypt being the poster child). #2 is what I did and that was based off of what is in the docker swarm setup and I *believe* what the Windows Internal CA does (I'm going based off colleague's explanation of behavior --- haven't looked at it myself). So, of these, #2 is really used just for private CAs... I think?Does that seem like coverage?Sure.So, I'm a bit torn as to the right thing to do, in large part because I think signing an existing cert can be useful and don't want to mandate a CSR, but for people getting a CSR from a new root and wanting that signed I want them to be able to as well.
That said, possibilities:1) Change sign-self-issued so that it puts the root CA's subject DN in the Issuer DN of the new cert. IOW it will keep the certificate as-is, just as it does now, but use the root CA as the parent cert (to update the Issuer info) rather than using the same cert for both parent/child and just changing the signing key. An open question with this approach is whether it then makes sense to require self-issued certs as a check, or whether it should just generally sign any cert that you're asking it to. Certainly that behavior could be relaxed later.
2) Add the ability to just give a certificate to sign-intermediate in addition to a CSR, so you can do whichever you want, but I'm not sure whether the use_csr_values approach is the right thing there because it does slightly modify things (ensures a basic set of key usages, for instance...sign-self-issued only updates configured URL values for issuing/ocsp/crls, which I thought made sense). And I'm a bit leery of adding both the ability to pop in a cert *and* a use_cert_values with a different meaning.
3) Allow sign-intermediate to issue child CAs with validity dates past the root CA if requested in the TTL parameter, defaulting (if no TTL is given) to the lifetime of the root CA cert.
What I'm leaning towards for now is to make the changes in #1 and #3. For #1, you submit your desired new self-issued CA and what you get out is a cert signed (in the normal sense, with the changed Issuer) by the root that otherwise keeps all other values intact (except, also, for the URLs, as mentioned before, and which I think make sense). You generate it with your desired subject, validity dates, etc.I believe between these two it would would fix your use case and indeed most use-cases we've discussed. If there's demonstrated need to allow signing other certs (as opposed to CSRs) that aren't self-issued that could be added later to either sign-self-issued (maybe renaming in the process) or sign-intermediate.Thoughts?
I'm of the mind that it can be pieced together from the RFCs. The Issuer field and the references to (Issuer of one is Subject of other) seem pretty close. Could be little-I issuer versus big-I Issuer, but.... <shrug>
I'm not sure on the terminology. Root and Intermediate seem to be incompletely defined with respect to how they're general used. Based on the "it's not si/ss" part, all certs after the first one will be Intermediate, but they're also going to be TAs so that kinda makes them Roots. Bleh... language is hard. That being said, I think calling them intermediates does fit the principle of least surprise (not *no* surprise, not *intuitive*, just *least*). If I think "what do I need to do?" I'll eventually get to "I should sign it like an intermediate since it's not si/ss."
I think the "sign-self-issued" name maybe should be something a bit more based on purpose (though that does feel like a trap). "reissue-self" or something like that seems to be a bit more on for its use cases.
This is enough of a edge case that I think it might be ok to force the CSR. There's generally two categories here:1.) If you've gotten to this point, you probably have done some general cert management before and know how to get a CSR - in fact, that's probably the way you're used to getting a Cert. "Well, I've got a si/ss root cert but I want to get it signed with this other root cert too. Oh, the docs say I need a CSR to be signed... oh, I've done that before so... ok." Depending on how you did it (single liner openssl req, or multiple step), you might even have a CSR you can use.2.) If you've been through having to handle root rolling, you probably have an idea of the complexities and getting a CSR is the least of your concerns ;).
Given my preference, I think #3 makes the most sense, but certainly can work within #1.Maybe it shouldn't be "sign-intermediate" but it should be "sign-ca" since that can mean "intermediate" or "something that will become a TA" or "reissue me" in all these cases, the CA is the crux. Taking an adoption/transition part out of the picture, that's really what this is for, right? If I submit to sign-ca with a CSR, then I'm expecting it to have the Issuer set to this CA. If I submit with a ss/si cert, then I expect it to be cross signed or (if DN matches this CA) a re-issuance with policy/key changes. I think it's a bit of do you want multiple explicit endpoints (and let's just then call them out what they're for - "reissue", "sign-TA", "sign-intermediate", "cross-sign") or a single endpoint that has different behavior based on what's fed into it?
Thanks,
--mac--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
GitHub Issues: https://github.com/hashicorp/vault/issues
IRC: #vault-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Vault" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vault-tool+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vault-tool/887eeb91-803d-4539-b735-655ce3c8f00d%40googlegroups.com.
OK, that all said, I have a favor to ask. Any chance I can get you to re-run the validation checks you ran before using the self-issued-wrong-pubkey branch? I realized as I was writing this that there's actually a bug in the code in that endpoint -- it's passing in the signing bundle's public key instead of the subject's public key. I can totally believe this would affect validation -- it should :-) So then the question becomes is validation actually working (which according to the class of self-issued CA certs in the RFC it feels like it *ought* to) with the right public key being signed :-/ In which case it's a simple bug fix for the endpoint to already do what you need!I've put an amd64 build of Vault with this fix at https://drive.google.com/open?id=0B9k5inNzLXz2N3BhU3VXQVNMVW8 (filename: vault-272cffe5fc2f51affb152fb41a2547ec33d8a805.bz2 sha256: b75af83d297930d27cc3936c7475bc0d99a360de3fdbe3d17f002c3282bfb5ce)
$ shasum -a 256 ../Desktop/vault/vault-272cffe5fc2f51affb152fb41a2547ec33d8a8059bd2d00a913bbe7c90210d4221b8629ba37b4c275280ee4da69af34f7cf94e0c ../Desktop/vault/vault-272cffe5fc2f51affb152fb41a2547ec33d8a805
$ go run vault-test-20170911-test.gopanic: x509: issuer name does not match subject from issuing certificategoroutine 1 [running]:main.main()/Users/cmceniry/Downloads/vault-test-20170911-test.go:42 +0x40cexit status 2$ openssl verify -CAfile ./vault-test-20170911-pkia vault-test-20170911-pkib-signed-by-pkiavault-test-20170911-pkib-signed-by-pkia: /CN=pki berror 20 at 0 depth lookup:unable to get local issuer certificate
vault mount -path pkia pkivault mount -path pkib pkivault write pkia/root/generate/internal common_name="pki a"vault read pkia/cert/ca ====> vault-test-20170911-pkiavault write pkib/root/generate/internal common_name="pki b"vault read pkib/cert/ca ====> vault-test-20170911-pkib-originalwrite pkia/root/sign-self-issued certificate=@vault-test-20170911-pkib-original =====> write pkia/root/sign-self-issued certificate=@vault-test-20170911-pkib-original
$ openssl verify -CAfile ./vault-test-20170911-pkia vault-test-20170911-pkib-signed-by-pkia
write pkia/root/sign-self-issued certificate=@vault-test-20170911-pkib-original =====> write pkia/root/sign-self-issued certificate=@vault-test-20170911-pkib-original
write pkia/root/sign-self-issued certificate=@vault-test-20170911-pkib-original =====> vault-test-20170911-pkib-signed-by-pkia
--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
GitHub Issues: https://github.com/hashicorp/vault/issues
IRC: #vault-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Vault" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vault-tool+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vault-tool/8584f1e9-4ccb-4f86-8ecf-8b4c0336de53%40googlegroups.com.
PR is up here, for anyone interested:
Odd about the shasum. I used sha256sum and maybe it required -b?
Thanks for testing again. (Normally I'd not be shoving such basic testing off to you, please believe me when I say "HashiConf" as an excuse for being lazy about this at the current time.)
It's too bad the bug fix doesn't solve the issuer problem, so I guess we'll have to proceed with the previously discussed changes. What I was hoping was that by using the right public key to be signed it might fix any validation errors caused by the subject key id being incorrect.
We'll get the changes in for 0.8.3.
--mac--
This mailing list is governed under the HashiCorp Community Guidelines - https://www.hashicorp.com/community-guidelines.html. Behavior in violation of those guidelines may result in your removal from this mailing list.
GitHub Issues: https://github.com/hashicorp/vault/issues
IRC: #vault-tool on Freenode
---
You received this message because you are subscribed to the Google Groups "Vault" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vault-tool+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/vault-tool/609019b7-cecb-401a-956d-5fd4b7b6aa0b%40googlegroups.com.