Ben Reser <b...@reser.org> writes:

> Not sure how you're processing those cert files (and you have to be doing
> something since our parser only accepts DER certs and most of those are PEM)
> but that's where the problem could be.  I'm writing a quick little command
> line tool that can read PEM, raw base64 encode certs (i.e. PEM without the
> header/footer) and DERs and feed them through our parser.  Which should make
> it trivial to test arbitrary certificates.

I grepped everything between BEGIN/END certificate markers and (with a bit
of post-processing) plugged the results into the 'x509_test cert_tests[]'
data set.  As a consequence, the PEM → DER conversion happened within the
test_x509_parse_cert() test.

> This may be a case of our parser being overly paranoid about the input data
> being consistent.  The buffer you pass to svn_x509_parse_cert() must end at
> exactly the place where the initial SEQUENCE says it should.  Put an extra 
> byte
> on the end and our parser will error out.

As it turns out, almost every failing certificate has X.509 Version: 1 (0x0),
but also happens to have V3 extensions.  These are ill-formed per RFC 5280
s. 4.1 [1], but we could encounter them in the real world.  For instance,
OpenSSL 1.0.1f does produce such certificates when signing end-entities
with the ee.cnf config from [2] (might be a bug).  Googling shows at least
one thread with a person having an X.509 V1 certificate with V3 extensions.

I tend to think that being too strict in this aspect might be harmful.  We
only want to display data in a certificate, and I think we should be able
to parse these certificates.  OpenSSL and Microsoft CryptoAPI do not error
out on them and show what's there in V3 extensions even if the certificate
itself is a V1.  For example, with 'openssl x509 -text -noout' I get:

    Data:
        Version: 1 (0x0)
        Serial Number: 15 (0xf)

        ...

        X509v3 extensions:
            X509v3 Subject Alternative Name:
                DNS:b.example.com

I came up with the attached patch for /branches/svn-auth-x509.  Log message:
[[[
On svn-auth-x509 branch: Try to parse issuerUniqueID, subjectUniqueID and
extensions for every X.509 certificate version (v1, v2 and v3).

If they aren't present, we are fine, but we don't want to throw an error if
they are.  v1 and v2 certificates with the corresponding extra fields are
ill-formed per RFC 5280 s. 4.1, but we suspect they could exist in the real
world.  Other X.509 parsers (e.g., within OpenSSL or Microsoft CryptoAPI)
aren't picky about these certificates.  As long as we are only willing to
display the certificate data in the 'svn auth' command, we can also be less
strict about them.

* subversion/libsvn_subr/x509parse.c
  (svn_x509_parse_cert): Try to parse issuerUniqueID, subjectUniqueID and
   extensions for all known X.509 versions (v1, v2, v3).
  (x509parse_get_hostnames): Do not check CRT->DNSNAMES for null, because
   it is no longer necessary.

  subversion/tests/libsvn_subr/x509-test.c
  (cert_tests): Add a new test case.
]]]

Now, the only remaining fail is the 'fail-2.cer.txt' from my previous e-mail,
which has multiple AttributeTypeAndValue entries in RelativeDistinguishedName
(RDN).  I am not yet sure why do we fail to parse the certificate, but the
certificate itself is structurally valid per RFC 5280 s. 4.1.2.4 [3].  Here
is what 'openssl asn1parse -dump' says about it (output trimmed):

  188:d=3  hl=2 l= 111 cons: SET
  190:d=4  hl=2 l=   9 cons: SEQUENCE
  192:d=5  hl=2 l=   3 prim: OBJECT            :countryName
  197:d=5  hl=2 l=   2 prim: PRINTABLESTRING   : ...
  201:d=4  hl=2 l=  15 cons: SEQUENCE
  203:d=5  hl=2 l=   3 prim: OBJECT            :organizationName
  208:d=5  hl=2 l=   8 prim: UTF8STRING        : ...
  218:d=4  hl=2 l=  22 cons: SEQUENCE
  220:d=5  hl=2 l=  10 prim: OBJECT            :domainComponent
  232:d=5  hl=2 l=   8 prim: IA5STRING         : ...
  242:d=4  hl=2 l=  26 cons: SEQUENCE
  244:d=5  hl=2 l=   3 prim: OBJECT            :commonName
  249:d=5  hl=2 l=  19 prim: UTF8STRING        : ...
  270:d=4  hl=2 l=  29 cons: SEQUENCE
  272:d=5  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
  277:d=5  hl=2 l=  22 prim: UTF8STRING        : ...

[1] https://tools.ietf.org/html/rfc5280#section-4.1
[2] https://src.chromium.org/svn/trunk/src/net/data/ssl/scripts/ee.cnf
[3] https://tools.ietf.org/html/rfc5280#section-4.1.2.4


Regards,
Evgeny Kotkov
Index: subversion/libsvn_subr/x509parse.c
===================================================================
--- subversion/libsvn_subr/x509parse.c  (revision 1655502)
+++ subversion/libsvn_subr/x509parse.c  (working copy)
@@ -1010,7 +1010,7 @@ x509parse_get_hostnames(svn_x509_certinfo_t *ci, x
 {
   ci->hostnames = NULL;
 
-  if (crt->dnsnames && crt->dnsnames->nelts > 0)
+  if (crt->dnsnames->nelts > 0)
     {
       int i;
 
@@ -1155,18 +1155,19 @@ svn_x509_parse_cert(svn_x509_certinfo_t **certinfo
    *      extensions              [3]      EXPLICIT Extensions OPTIONAL
    *                                               -- If present, version 
shall be v3
    */
-  if (crt->version == 2 || crt->version == 3)
-    SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1));
+  crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *));
 
-  if (crt->version == 2 || crt->version == 3)
-    SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2));
+  /* Try to parse issuerUniqueID, subjectUniqueID and extensions for *every*
+   * version (X.509 v1, v2 and v3), not just v2 or v3.  If they aren't present,
+   * we are fine, but we don't want to throw an error if they are.  v1 and v2
+   * certificates with the corresponding extra fields are ill-formed per RFC
+   * 5280 s. 4.1, but we suspect they could exist in the real world.  Other
+   * X.509 parsers (e.g., within OpenSSL or Microsoft CryptoAPI) aren't picky
+   * about these certificates, and we also allow them. */
+  SVN_ERR(x509_get_uid(&p, end, &crt->issuer_id, 1));
+  SVN_ERR(x509_get_uid(&p, end, &crt->subject_id, 2));
+  SVN_ERR(x509_get_ext(crt->dnsnames, &p, end));
 
-  if (crt->version == 3)
-    {
-      crt->dnsnames = apr_array_make(scratch_pool, 3, sizeof(x509_buf *));
-      SVN_ERR(x509_get_ext(crt->dnsnames, &p, end));
-    }
-
   if (p != end)
     {
       err = svn_error_create(SVN_ERR_ASN1_LENGTH_MISMATCH, NULL, NULL);
Index: subversion/tests/libsvn_subr/x509-test.c
===================================================================
--- subversion/tests/libsvn_subr/x509-test.c    (revision 1655502)
+++ subversion/tests/libsvn_subr/x509-test.c    (working copy)
@@ -437,6 +437,39 @@ static struct x509_test cert_tests[] = {
     "x509v1.example.com",
     "5730dd65a7f77fdf0dfd90e5a53119f38854af29"
   },
+  /* X.509 v1 certificate with an X.509 v3 Subject Alternative Name
+   * extension.  Although these are ill-formed per RFC 5280 s. 4.1, we
+   * suspect that they could exist in the real world.  Make sure we do
+   * not error out, and that we pick up SAN (b.example.com) from the
+   * extension. */
+  { "MIIDLzCCAhcCAQ8wDQYJKoZIhvcNAQEFBQAwKzEpMCcGA1UEAwwgSW50ZXJuZXQg"
+    "V2lkZ2l0cyBJbnRlcm1lZGlhdGUgQ0EwHhcNMTUwMTI5MDAzMzU1WhcNMTYwMTI5"
+    "MDAzMzU1WjByMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjETMBEG"
+    "A1UEBwwKTm9ydGggQmVuZDEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg"
+    "THRkMRYwFAYDVQQDDA1hLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC"
+    "AQ8AMIIBCgKCAQEAs0hj2xPRQZpecqk0Ih1l4juAuQZeSgv3yD/VtSq/9sTBH6iA"
+    "4XjJQcHROYxYaK0QS/qlCjpl+Q3mOaVIu+59TLy3T2YVgqMYmgB453ntuJPkdF1C"
+    "fJ2j19YAQZHHdOFaP1G+auBwjmHns3+MkG4s7EPuJP7TBCcSFlOmz5D4GUui3NVG"
+    "LBYUog1ZhF4oe/7d4jc2Cn8uypNT/Hc1ViIlCT4rFoAirv9Uob+4zjQ3Z18I1Ql1"
+    "t8oszVCj3kKDboEty2RduwPLx/2ztWYBCvFhd49JGdi/nzMi+j2d5HCI3V8W06pN"
+    "mvrVU4G0ImVRa8wpmQCSm2Tp0s42FAVHWw8yMwIDAQABoxwwGjAYBgNVHREEETAP"
+    "gg1iLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQDI/n0NYakuRP/485/A"
+    "dan71qBy3sljjOreq71IfBdtq+GEjCL1B0TD0V338LXki9NicCLeD/MWfceDjV0u"
+    "AjPTxaZEn/NWqXo0mpNC535Y6G46mIHYDGC8JyvCJjaXF+GVstNt6lXzZp2Yn3Si"
+    "K57uVb+zz5zAGSO982I2HACZPnF/oAtp7bwxzwvBsLqSLw3hh0ATVPp6ktE+WMoI"
+    "X75CVcDmU0zjXqzKiFPKeTVjQG6YxgvplMaag/iNngkgEhX4PIrxdIEsHf8l9ogC"
+    "dz51MFxetsC4D2KRq8IblF9i+9r3hlv+Dbf9ovYe9Hu0usloSinImoWOw42iWWmP"
+    "vT4l",
+    "C=US, ST=Washington, L=North Bend, O=Internet Widgits Pty Ltd, "
+    "CN=a.example.com",
+    "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3",
+    "CN=Internet Widgits Intermediate CA",
+    "2.5.4.3",
+    "2015-01-29T00:33:55.000000Z",
+    "2016-01-29T00:33:55.000000Z",
+    "b.example.com",
+    "47fa5c76fee6e21e37def6da3746bba84a5a09bf"
+  },
   { NULL }
 };
 

Reply via email to