Fix leak in set_dist_point_name error handling.

The temporary X509_NAME wasn't destroyed if the section didn't exist.
Also document the weird 0 vs -1 convention (see callers), and revise the
NULL check added in
https://boringssl-review.googlesource.com/c/boringssl/+/56705. It
doesn't make a difference, but we should only apply the NULL check after
we've looked at the name, and return -1 because, after the name is
checked, it's a known syntax error.

Also fix a couple of comments that were wrong. It's that the RDNSequence
we take from X509_NAME must have one RDN, not that there's one
RDNSequence. (This is a consequence of X509_NAME's somewhat odd
in-memory representation.)

Bug: oss-fuzz:55700
Change-Id: I5745752bfa82802d361803868f962b2b0fa4bd32
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/56929
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 4760044..e152f3d 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -5733,6 +5733,35 @@
       // value is not allowed.
       {"issuingDistributionPoint", "fullname", nullptr, {}},
 
+      {"issuingDistributionPoint",
+       "relativename:name",
+       "[name]\nCN=Hello\n",
+       {0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x1c, 0x04, 0x14, 0x30,
+        0x12, 0xa0, 0x10, 0xa1, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55,
+        0x04, 0x03, 0x0c, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f}},
+
+      // relativename referencing a section which doesn't exist.
+      {"issuingDistributionPoint",
+       "relativename:wrong_section_name",
+       "[name]\nCN=Hello\n",
+       {}},
+
+      // relativename must be a single RDN. By default, the section-based name
+      // syntax puts each attribute into its own RDN.
+      {"issuingDistributionPoint",
+       "relativename:name",
+       "[name]\nCN=Hello\nC=US\n",
+       {}},
+
+      // A single RDN with multiple attributes is allowed.
+      {"issuingDistributionPoint",
+       "relativename:name",
+       "[name]\nCN=Hello\n+C=US\n",
+       {0x30, 0x26, 0x06, 0x03, 0x55, 0x1d, 0x1c, 0x04, 0x1f, 0x30,
+        0x1d, 0xa0, 0x1b, 0xa1, 0x19, 0x30, 0x09, 0x06, 0x03, 0x55,
+        0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x0c, 0x06, 0x03,
+        0x55, 0x04, 0x03, 0x0c, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f}},
+
       // Duplicate reason keys are an error. Reaching this case is interesting.
       // The value can a string like "key:value,key:value", or it can be
       // "@section" and reference a config section. If using a string, duplicate
diff --git a/crypto/x509v3/v3_crld.c b/crypto/x509v3/v3_crld.c
index 0206c7a..a3cae42 100644
--- a/crypto/x509v3/v3_crld.c
+++ b/crypto/x509v3/v3_crld.c
@@ -127,27 +127,30 @@
   return gens;
 }
 
+// set_dist_point_name decodes a DistributionPointName from |cnf| and writes the
+// result in |*pdp|. It returns 1 on success, -1 on error, and 0 if |cnf| used
+// an unrecognized input type. The zero return can be used by callers to support
+// additional syntax.
 static int set_dist_point_name(DIST_POINT_NAME **pdp, const X509V3_CTX *ctx,
                                const CONF_VALUE *cnf) {
-  // If |cnf| comes from |X509V3_parse_list|, which is possible for a v2i
-  // function, |cnf->value| may be NULL.
-  if (cnf->value == NULL) {
-    OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE);
-    return 0;
-  }
-
   STACK_OF(GENERAL_NAME) *fnm = NULL;
   STACK_OF(X509_NAME_ENTRY) *rnm = NULL;
   if (!strncmp(cnf->name, "fullname", 9)) {
+    // If |cnf| comes from |X509V3_parse_list|, which is possible for a v2i
+    // function, |cnf->value| may be NULL.
+    if (cnf->value == NULL) {
+      OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE);
+      return -1;
+    }
     fnm = gnames_from_sectname(ctx, cnf->value);
     if (!fnm) {
       goto err;
     }
   } else if (!strcmp(cnf->name, "relativename")) {
-    int ret;
-    X509_NAME *nm;
-    nm = X509_NAME_new();
-    if (!nm) {
+    // If |cnf| comes from |X509V3_parse_list|, which is possible for a v2i
+    // function, |cnf->value| may be NULL.
+    if (cnf->value == NULL) {
+      OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE);
       return -1;
     }
     const STACK_OF(CONF_VALUE) *dnsect = X509V3_get_section(ctx, cnf->value);
@@ -155,14 +158,18 @@
       OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND);
       return -1;
     }
-    ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
+    X509_NAME *nm = X509_NAME_new();
+    if (!nm) {
+      return -1;
+    }
+    int ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC);
     rnm = nm->entries;
     nm->entries = NULL;
     X509_NAME_free(nm);
     if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0) {
       goto err;
     }
-    // Since its a name fragment can't have more than one RDNSequence
+    // There can only be one RDN in nameRelativeToCRLIssuer.
     if (sk_X509_NAME_ENTRY_value(rnm, sk_X509_NAME_ENTRY_num(rnm) - 1)->set) {
       OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_MULTIPLE_RDNS);
       goto err;
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index e3ba8e0..f38574f 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -938,7 +938,7 @@
 // success or zero on error. The entry's attribute type is |obj|. The entry's
 // attribute value is determined by |type|, |bytes|, and |len|, as in
 // |X509_NAME_ENTRY_set_data|. The entry's position is determined by |loc| and
-// |set| as in |X509_NAME_entry|.
+// |set| as in |X509_NAME_add_entry|.
 OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name,
                                               const ASN1_OBJECT *obj, int type,
                                               const uint8_t *bytes, int len,