<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <div class="moz-cite-prefix">On 01.01.21 08:07, 定平袁 wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CABYODQ9qnvoH3pBdZYAs9WUXKTY3Hw4AWajeXBQ_okctGJvcRQ@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <div dir="ltr"><a class="gmail_plusreply" id="plusReplyChip-8"
          href="mailto:dev@ddvo.net" tabindex="-1"
          moz-do-not-send="true">@David von Oheimb</a>
        <div> Thank you so much for your deep investigation!<br>
        </div>
      </div>
    </blockquote>
    My pleasure!<br>
    <br>
    <blockquote type="cite"
cite="mid:CABYODQ9qnvoH3pBdZYAs9WUXKTY3Hw4AWajeXBQ_okctGJvcRQ@mail.gmail.com">
      <div dir="ltr">
        <div>With subjectKeyIdentifier and authorityKeyIdentifier
          extensions, it works like a charm! <br>
        </div>
      </div>
    </blockquote>
    Good to hear.<br>
    I've meanwhile submitted a pull request that fixed the behavior
    also  in case no SKID and AKID are included in the certs<br>
    and briefly mentioned your use case there: <a
      moz-do-not-send="true"
      href="https://github.com/openssl/openssl/pull/13748">https://github.com/openssl/openssl/pull/13748</a><br>
    <br>
    <blockquote type="cite"
cite="mid:CABYODQ9qnvoH3pBdZYAs9WUXKTY3Hw4AWajeXBQ_okctGJvcRQ@mail.gmail.com">
      <div dir="ltr">
        <div>So, the former statements I found on <a
href="https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_load_verify_locations.html"
            moz-do-not-send="true">this page</a> only applies to CA
          cert, not EE cert. <br>
        </div>
        <div>How to pick up cert from trust store(or cert container as
          you say) <br>
        </div>
        <div>is decided by different implementation themselves, do I
          understand correctly?<br>
        </div>
      </div>
    </blockquote>
    It looks like my explanations were a bit mistakable.<br>
    Although self-signed (and more generally, self-issued) EE certs are
    out of scope of RFC 5280, OpenSSL still tries to build a cert chain
    for them and then to verify it.<br>
    Please also note that I did not write "cert container", but that
    these certs are essentially just a convenient container <i>for a
      public key</i>.<br>
    In other words, they have the <i>format</i> of an X.509
    certificate, but the only thing that really matters in such a cert
    is the public key.<br>
    Yet since they look like a certificate, they can be used where a
    certificate is expected, e.g., in TLS handshake and in trust stores.<br>
    <br>
    <blockquote type="cite"
cite="mid:CABYODQ9qnvoH3pBdZYAs9WUXKTY3Hw4AWajeXBQ_okctGJvcRQ@mail.gmail.com">
      <div dir="ltr">
        <div>Since GnuTls and golang could pick up the right cert in
          this kind of scenario, <br>
        </div>
        <div>they must implement their own logic to pick up the right
          cert, do you think OpenSSL</div>
        <div>will implement this logic too? Or it's a more appropriate
          approach to just <br>
        </div>
        <div>use the extensions you suggested?<br>
        </div>
      </div>
    </blockquote>
    With the fix mentioned above, chain building and verification will
    always succeed,<br>
    regardless how the cert looks like because in this case it is
    sufficient to find the target certificate in the trust store,<br>
    without having to check and further data that may be included in it.<br>
    Although not required by RFC 5280 for such a cert, OpenSSL does
    check for its expiration <br>
    (and may check policy restrictions etc.) because this is helpful in
    most application scenarios.<br>
    <p>Regards,</p>
    <p>    David</p>
    <p><br>
    </p>
    <blockquote type="cite"
cite="mid:CABYODQ9qnvoH3pBdZYAs9WUXKTY3Hw4AWajeXBQ_okctGJvcRQ@mail.gmail.com">
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">David von Oheimb <<a
            href="mailto:dev@ddvo.net" moz-do-not-send="true">dev@ddvo.net</a>>
          于2020年12月26日周六 下午5:17写道:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px
          0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div>
            <div>On 25.12.20 00:35, 定平袁 wrote:<br>
            </div>
            <blockquote type="cite">
              <div dir="ltr">
                <div><a class="gmail_plusreply"
                    id="gmail-m_-7525524058374870488m_1380141081388625801plusReplyChip-2"
                    href="mailto:dev@ddvo.net" target="_blank"
                    moz-do-not-send="true">@David von Oheimb</a> I will
                  update to a new version and try again.</div>
              </div>
            </blockquote>
            <p>Good. Ideally try also a current 3.0.0 alpha release
              because there have been some changes to cert chain
              building and verification recently.<br>
              <br>
            </p>
            <blockquote type="cite">
              <div dir="ltr">
                <div> To append cert is to make sure new cert and old
                  cert both exist in trust store, thus when server
                  switches cert, it can be trusted by client.<br>
                </div>
              </div>
            </blockquote>
            Understood, but my point was on a different aspect:<br>
            The chain building will take the first matching cert, so if
            you want to prefer the new cert, it must be in the list
            *before* the old one -<br>
            in other words, prepend the new cert to the list rather than
            appending to it.<br>
            <br>
            <blockquote type="cite">
              <div dir="ltr">
                <div>
                  <div>@Jochen actually, the certs have different SN,
                    which indeed is not consistent with the man doc</div>
                </div>
              </div>
            </blockquote>
            <p>Different certs with the same issuer indeed <b>must</b>
              have different SNs (except in the special case I mention
              below). <br>
              See also RFC 5280 section 4.1.2.2 <a
                href="https://tools.ietf.org/html/rfc5280#section-4.1.2.2"
                target="_blank" moz-do-not-send="true">https://tools.ietf.org/html/rfc5280#section-4.1.2.2</a>:<br>
            </p>
            <pre>  It MUST be unique for each certificate issued by a given CA
     (i.e., the issuer name and serial number identify a unique certificate). </pre>
            <p><br>
              Yet there is a different inconsistency in what you write:</p>
            <blockquote type="cite">
              <div dir="ltr">
                <div>
                  <div>The thing that confuses me is that CURL (compiled
                    with gnutls) and Golang works. <br>
                  </div>
                  <div>below is my ca.crt file, I am not sure where it
                    went wrong, maybe just my wrong behavior?</div>
                </div>
              </div>
            </blockquote>
            You refer to them as CA certs, but they are not: they do no
            have a basicConstraints field with the cA bit set.<br>
            And as far as I understand your scenario, they are not used
            to issue other certs but by some (TLS) server,<br>
            so they really are end-entity (EE) certs, not CA certs, and
            it looks like this is correct in your application scenario.<br>
            <br>
            Directly trusted self-issued EE certs (which may be
            self-signed or not) are a special situation.<br>
            This has been clarified in RFC 6818 (which updates RFC 5280)
            <a href="https://tools.ietf.org/html/rfc6818#section-2"
              target="_blank" moz-do-not-send="true">https://tools.ietf.org/html/rfc6818#section-2</a>:<br>
            <pre>| Consistent with <a href="https://tools.ietf.org/html/rfc6818#section-3.4.61" target="_blank" moz-do-not-send="true">Section 3.4.61</a> of X.509 (11/2008) [<a href="https://tools.ietf.org/html/rfc6818#ref-X.509" target="_blank" moz-do-not-send="true">X.509</a>], we note
| that use of self-issued certificates and self-signed certificates
| issued by entities other than CAs are outside the scope of this
| specification.  Thus, for example, a web server or client might
| generate a self-signed certificate to identify itself.  These
| certificates and how a relying party uses them to authenticate
| asserted identities are both outside the scope of <a href="https://tools.ietf.org/html/rfc5280" target="_blank" moz-do-not-send="true">RFC 5280</a>.</pre>
            So the path building and verification, as well as other
            checks defined RFC 5280, does not apply to them at all!<br>
            They are essentially just a convenient container for a
            public key, where it is optional to check expiration etc.<br>
            <p><br>
              Unfortunately, when using such certs for TLS connections
              etc., still verification is done on them, which may fail.<br>
              After renaming your ca.crt file to ee.crt for clarity and
              extracting the first cert in ee1.crt and the second one in
              ee2.crt,<br>
              when verifying these directly trusted certs one gets the
              problem you reported:<br>
              <br>
              openssl verify -x509_strict -trusted ee.crt ee1.crt<br>
              ee1.crt: OK<br>
            </p>
            <p>openssl verify -x509_strict -trusted ee.crt ee2.crt<br>
              C = US, ST = CA, L = Palo Alto, O = VMware, CN =
              nsxmanager.pks.vmware.local<br>
              error 18 at 0 depth lookup: self signed certificate<br>
              error ee2.crt: verification failed<br>
            </p>
            <p>So as I wrote before, unfortunately the path building
              picks up the first matching cert from ee.crt,<br>
              which is the one in ee1.crt (i.e., your old one), and does
              not try the second one (i.e., your new one).<br>
              This happens also with the latest OpenSSL pre-3.0.0
              master.<br>
            </p>
            <p><br>
              A solution is to add both the subjectKeyIdentifier and
              authorityKeyIdentifier extensions to your certs,<br>
              for instance like this:<br>
            </p>
            <p>echo >ee.cnf "<br>
              prompt = no<br>
              distinguished_name = my_server<br>
              x509_extensions = my_exts<br>
              [my_server]<br>
              commonName = test<br>
              [my_exts]<br>
              basicConstraints = CA:false<br>
              subjectKeyIdentifier=hash<br>
              authorityKeyIdentifier = keyid"<br>
            </p>
            <p>openssl req -config ee.cnf -new -x509 -out ee1.crt -nodes
              -keyout ee1.pem<br>
              openssl req -config ee.cnf -new -x509 -out ee2.crt -nodes
              -keyout ee2.pem<br>
              cat ee1.crt ee2.crt >ee.crt</p>
            <p>The subjectKeyIdentifier and authorityKeyIdentifier
              extensions are generally recommend<br>
              (and actually required to add for certs that are RFC 5280
              compliant) <br>
              because they help for correct chain building, and indeed
              also in this case they do:<br>
            </p>
            <p>openssl verify -x509_strict -trusted ee.crt ee1.crt<br>
              ee1.crt: OK<br>
              openssl verify -x509_strict -trusted ee.crt ee2.crt<br>
              ee2.crt: OK<br>
              <br>
            </p>
            <p>Regards,</p>
            <p>    David<br>
            </p>
            <br>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </body>
</html>