Subject: Recommended changes to draft-ietf-pkix-new-part1-08

From: Peter Hesse <[email-masked]>
Date: Tue, 21 Aug 2001 10:24:08 -0400

All,

I realize these comments are coming quite late in the process, and I hope
not to cause too much of a problem.  However, I feel that standards need to
be quite explicit in certain areas, and the current draft of the Internet
X.509 Public Key Infrastructure Certificate and CRL Profile (son of 2459) is
still a bit ambiguous when it comes to processing self-signed trust anchor
certificates.  I propose two changes in order to reduce this ambiguity.
First I will quote from the current draft, section 6.1:

--------------------------------------------------------------------------
   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; and

      (d)  for all x in {1, ..., n}, the certificate was valid at the
      time in question.
--------------------------------------------------------------------------

In my opinion, (b) should be changed to explicity specify that certificate 1
is not a self-signed certificate issued by the trust anchor.  

The second change is needed because the logic of section 6.1 does not
specifically say what certificates are subject to the validation processing
other than the part quoted above.  My second recommendation is to change the
beginning of 6.1.3 to the following: 

--------------------------------------------------------------------------
The basic path processing actions to be performed for certificate i 
(for all i in [1...n]) are listed below.
--------------------------------------------------------------------------

These changes would allow certainty that 
- certificate 1 is not the self-signed trust anchor certificate
- only certificates 1...n are processed, therefore explicitly not processing
a self-signed trust anchor certificate if one exists in the path.

Again, apologies for bringing this up so late, but I feel this issue is
quite important for interoperability between path validation
implementations.

--Peter

---------------------------------------------------------------- 
 Peter M. Hesse            CygnaCom Solutions, a division of
 Phone: 703-270-3523                   Entrust
 ICQ:   1942828                 Securing the Internet
---------------------------------------------------------------- 
"Pay no attention to what the critics say; there has never been 
a statue set up in honor of a critic." --Jean Sibelius

---

From: Steve Hanna <[email-masked]>
Date: Tue, 21 Aug 2001 13:58:33 -0400

The current document seems clear to me, but I've been working with it
for years! ;-) Making it clearer is certainly a good idea and I support
these changes. I believe they fall into the category of minor editorial
changes to clarify the meaning already present in the document and
agreed to by the working group. Therefore, I don't think there should be
any problem with making these changes, even at this late date.

Let me make a few minor comments and offer some specific text for the
first change so we have something specific to discuss.

> Peter Hesse wrote:
> In my opinion, (b) should be changed to explicity specify that
> certificate 1 is not a self-signed certificate issued by the trust
> anchor.

Actually, certificate 1 *could* be the self-signed certificate if for
some reason the path actually happened to start with that certificate.
That would be unusual, but I do not think we should explicitly forbid
it. But I agree that it would be good to supply explicit guidance at
this point in the document that the trust anchor should not normally be
included in the path validation procedure.

In order to have a specific textual change to discuss, I'll suggest that
immediately following point (d) above, a sentence (a new paragraph, I
suppose) be added that says:

   When the trust anchor is provided in the form of a self-signed
   certificate, this certificate is not included as a part of the
   prospective certification path.

> specifically say what certificates are subject to the validation
> processing other than the part quoted above.

Actually, section 6.1 says "Step (2) is performed for all certificates
in the path." Step (2) is defined elsewhere as Basic Certificate
Processing, which is discussed in section 6.1.3. And, in the section you
quoted above, it defines the "prospective certification path"  as "a
sequence of n certificates".

But I still think that your suggestion below is a good one. It's useful
to say the same thing two or three times to make sure there's no
misunderstanding, especially since this is a change from RFC 2459, where
the trust anchor *was* included in the path for validation purposes.

>  My second recommendation
> is to change the beginning of 6.1.3 to the following:
> 
> - only certificates 1...n are processed, therefore explicitly not
> processing a self-signed trust anchor certificate if one exists in the
> path.
> 
> Again, apologies for bringing this up so late, but I feel this issue
> is quite important for interoperability between path validation
> implementations.

Thanks for bringing it up. It's good to make the document clearer. I
just hope we don't descend into a long debate now...

Steve Hanna
Sun Microsystems, Inc.

---

From: Jeff Jacoby <[email-masked]>
Date: Tue, 21 Aug 2001 15:12:26 -0700

To all,

Jumping on the bandwagon here...

There are three points I believe could use clarification (at least 
I'm having trouble grokking them).

Section 6.1.4 Preperation for certificate i+1, step (b)(1). the
second paragraph reads:

  "If no node of depth i in the valid_policy_tree has a
   valid_policy of ID-P but there is a node of depth i with a
   valid_policy of any-policy, then generate a child node of the
   node of depth i-1 that has a valid_policy of any-policy as
   follows:"

Should it really be:

  "If no node of depth i in the valid_policy_tree has a
   valid_policy of ID-P but there is a node of depth i-1 with a
   valid_policy of any-policy, then generate a child node of the
   node of depth i-1 that has a valid_policy of any-policy as
   follows:"

(note the difference in the first sentence, "i" vs "i-1").  Afterall,
the last sentence implies there must be a node of depth i-1 with a
valid_policy of any-policy.

Second issue is a simple typo.  The very last sentence in section 6.1.4
reads:

  "If (a), (k), (l), (n) and (o) have completed successfully, increment
   i and perform the basic certificate processing specified in 6.1.2."

it should be:

  "If (a), (k), (l), (n) and (o) have completed successfully, increment
   i and perform the basic certificate processing specified in 6.1.3."

(6.1.2 is Initialization)

Finally, in the wrap-up description, section 6.1.5 step (g)(iii) 1.
reads:

  "1.  Determine the set of policy nodes whose ancestor nodes
   have a valid_policy of any-policy.  This is the
valid_policy_node_set."

Since the root node (depth 0) has valid_policy of any-policy, and it is
an ancestor to every node in the tree, this would seem to mean (to me)
the whole tree is in the valid_policy_node_set.  Or does "ancestor node"
mean something different?

Thanks,

Jeff

-- 
Jeff Jacoby, Sr. Programmer                
RSA Security Inc., SMDC                    [email-masked]
2755 Campus Dr., Ste. 300                  (650) 295-7569
San Mateo, CA  94403

---

From: Jeff Jacoby <[email-masked]>
Date: Wed, 22 Aug 2001 14:41:11 -0700

> I'm having trouble grokking them).

One more minor item.  The term "any-policy" is used 
throughout the document .  However, the ASN.1 name 
is anyPolicy:

    anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificate-policies 0 }

and in fact "anyPolicy" is also used in several places in the
document.  

Is the use of "any-policy" meant to imply a difference from "anyPolicy", 
or do these two terms really mean the exact same thing?  If the latter,
then 
I believe "any-policy" should be replaced by "anyPolicy" throughout.

Jeff

---

From: "David A. Cooper" <[email-masked]>
Date: Thu, 23 Aug 2001 08:57:46 -0400

Jeff,

any-policy and anyPolicy are different, although the difference is somewhat subtle.  The term any-policy is essentially a mathematical variable representing the set of all possible certificate policies (i.e., any-policy = {OID | OID is an object identifier that represents a certificate policy}).  anyPolicy, on the other hand, is a variable defined in an ASN.1 module and it represents a specific object identifier (anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificate-policies 0 }).

So, anyPolicy is an object identifier that may appear in the certificatePolicies extension of a certificate.  any-policy represents a mathematical value that can be the value of a state variable in section 6 (e.g., user-initial-policy-set, expected_policy_set).

At least, this was the intention.  In responding to your question I noticed that "any-policy" was sometimes used where "anyPolicy" should have been.  This will need to be corrected.

Dave

---

From: "David A. Cooper" <[email-masked]>
Date: Sat, 25 Aug 2001 16:10:53 -0400

>valid_policy of any-policy.

Actually, I believe that the original text was correct. To see why, consider the following two examples:

In the first example, the first certificate in the path contains the following policy extensions:

certificatePolicies = {anyPolicy, a}
policyMappings = {a --> c, b --> d}

After carrying out the steps in section 6.1.3, the valid_policy_tree, excluding the qualifier_set and criticality_indicator fields, would be (NOTE: this is best viewed with a fixed-width font):

               +----------------+
               |   any-policy   |   <---- valid_policy
               +----------------+
               |   any-policy   |   <---- expected_policy_set
               +----------------+
                  /            \
                 /              \
+----------------+            +----------------+
|   any-policy   |            |       a        |  <---- valid_policy
+----------------+            +----------------+
|   any-policy   |            |      {a}       |  <---- expected_policy_set
+----------------+            +----------------+

After the policy mappings extension is processed, the result is:

                    +----------------+
                    |   any-policy   |   <---- valid_policy
                    +----------------+
                    |   any-policy   |   <---- expected_policy_set
                    +----------------+
                   /        |         \
                  /         |          \
+----------------+ +----------------+ +----------------+
|   any-policy   | |       b        | |       a        | <---- valid_policy
+----------------+ +----------------+ +----------------+
|   any-policy   | |      {d}       | |      {c}       | <---- expected_policy_set
+----------------+ +----------------+ +----------------+

In this case, the result would be the same whether the current text or the proposed text were used. Note that, by construction, if there is a node of depth i with valid_policy any-policy, there must also be a node of depth i-1 with valid_policy any-policy.

The second example shows a case in which the two algorithms differ. In this case, the first certificate in the path contains the following policy extensions:

certificatePolicies = {a}
policyMappings = {a --> c, b --> d}

+----------------+
|   any-policy   |   <---- valid_policy
+----------------+
|   any-policy   |   <---- expected_policy_set
+----------------+
                |
                |
+----------------+
|      a         |   <---- valid_policy
+----------------+
|     {a}        |   <---- expected_policy_set
+----------------+

When the policy mappings extension is processed, the expected_policy_set for the node at depth 1 is changed from {a} to {c}. Since there is no node of depth 1 with a valid_policy of any-policy, the mapping from b to d is ignored. The result is:

+----------------+
|   any-policy   |   <---- valid_policy
+----------------+
|   any-policy   |   <---- expected_policy_set
+----------------+
                |
                |
+----------------+
|      a         |   <---- valid_policy
+----------------+
|     {c}        |   <---- expected_policy_set
+----------------+

If the proposed text were followed, a node of depth i with a valid_policy of b and expected_policy_set of {d} would be created. However, this would make it appear as if b appeared in the certificatePolicies extension.  In the first example, this was OK since b was implicitly included in the certificatePolicies extension through the inclusion of anyPolicy. In the second example, however, b was neither explicitly nor implicitly included in the certificatePolicies extension. So, in the second example, b should not appear as the valid_policy in any node of depth i.

So, in effect, the phrase "if ... there is a node of depth i with a valid_policy of any-policy" is checking to see if anyPolicy was included in the certificatePolicies extension. If so, then the issuing domain policy ID-P was implicitly included in the certificatePolicies extension and the mapping from the issuing domain policy to the subject domain policy can be included in the valid_policy tree just as if the issuing domain policy had been explicitly included in the certificatePolicies extension. If neither the issuing domain policy nor anyPolicy was included in the certificatePolicies extension, then the mapping should be ignored.

>(6.1.2 is Initialization)

Good catch.

>mean something different?

I believe that "ancestor" should be replaced by "parent".  The idea is to compare policies from the user-initial-policy-set to policies in the valid_policy_tree that came from the domain of the relying party. Thus, we must look at nodes in the valid_policy_tree as close to the root as possible, before any policy mappings have taken place. If a node's parent has a valid_policy of any-policy, then no policy mappings could have been performed in any of that node's ancestors (i.e., in each of the node's ancestors, the expected_policy_set and the valid_policy are both any-policy) and so it is reasonable to check whether that node's valid_policy appears in the user-initial-policy-set.  If a node's parent vald_policy other than any-policy then either a policy mapping has occurred (in which case the node's valid_policy should not be compared to the user-initial-policy-set) or no mapping has occurred (in which case one or more of the node's ancestors contains the same valid_policy, and one of those ancestor nodes will be compared against the user-initial-policy-set).

Dave

---

From: Jeff Jacoby <[email-masked]>
Date: Mon, 27 Aug 2001 10:08:48 -0700

Dave,

Thank you for the answers (and also to the other question I'd
had on "any-policy"), they are of enormous help.  Excellent 
artwork, too! 

Jeff

"David A. Cooper" wrote:
> After carrying out the steps in section 6.1.3, the valid_policy_tree,
> excluding the qualifier_set and criticality_indicator fields, would be
> (NOTE: this is best viewed with a fixed-width font):
> 
>               +----------------+
> In this case, the result would be the same whether the current text or
> the proposed text were used. Note that, by construction, if there is a
> node of depth i with valid_policy any-policy, there must also be a node
> of depth i-1 with valid_policy any-policy.
> 
> The second example shows a case in which the two algorithms differ. In
> this case, the first certificate in the path contains the following
> policy extensions:
> 
> When the policy mappings extension is processed, the expected_policy_set
> for the node at depth 1 is changed from {a} to {c}. Since there is no
> node of depth 1 with a valid_policy of any-policy, the mapping from b to
> d is ignored. The result is:
> 
> +----------------+
> If the proposed text were followed, a node of depth i with a
> valid_policy of b and expected_policy_set of {d} would be created.
> However, this would make it appear as if b appeared in the
> certificatePolicies extension.  In the first example, this was OK since
> b was implicitly included in the certificatePolicies extension through
> the inclusion of anyPolicy. In the second example, however, b was
> neither explicitly nor implicitly included in the certificatePolicies
> extension. So, in the second example, b should not appear as the
> valid_policy in any node of depth i.
> 
> So, in effect, the phrase "if ... there is a node of depth i with a
> valid_policy of any-policy" is checking to see if anyPolicy was included
> in the certificatePolicies extension. If so, then the issuing domain
> policy ID-P was implicitly included in the certificatePolicies extension
> and the mapping from the issuing domain policy to the subject domain
> policy can be included in the valid_policy tree just as if the issuing
> domain policy had been explicitly included in the certificatePolicies
> extension. If neither the issuing domain policy nor anyPolicy was
> included in the certificatePolicies extension, then the mapping should
> be ignored.
> 
> I believe that "ancestor" should be replaced by "parent".  The idea is
> to compare policies from the user-initial-policy-set to policies in the
> valid_policy_tree that came from the domain of the relying party. Thus,
> we must look at nodes in the valid_policy_tree as close to the root as
> possible, before any policy mappings have taken place. If a node's
> parent has a valid_policy of any-policy, then no policy mappings could
> have been performed in any of that node's ancestors (i.e., in each of
> the node's ancestors, the expected_policy_set and the valid_policy are
> both any-policy) and so it is reasonable to check whether that node's
> valid_policy appears in the user-initial-policy-set.  If a node's parent
> vald_policy other than any-policy then either a policy mapping has
> occurred (in which case the node's valid_policy should not be compared
> to the user-initial-policy-set) or no mapping has occurred (in which
> case one or more of the node's ancestors contains the same valid_policy,
> and one of those ancestor nodes will be compared against the
> user-initial-policy-set).
> 
> Dave