summaryrefslogtreecommitdiff
path: root/lib/x509/dn.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/x509/dn.c')
-rw-r--r--lib/x509/dn.c341
1 files changed, 207 insertions, 134 deletions
diff --git a/lib/x509/dn.c b/lib/x509/dn.c
index 7209cdb92f..3395941403 100644
--- a/lib/x509/dn.c
+++ b/lib/x509/dn.c
@@ -33,194 +33,215 @@
* Name (you need a parser just to read a name in the X.509 protocols!!!)
*/
-int
-_gnutls_x509_get_dn(ASN1_TYPE asn1_struct,
- const char *asn1_rdn_name, gnutls_datum_t * dn)
+static int append_elements(ASN1_TYPE asn1_struct, const char *asn1_rdn_name, gnutls_buffer_st *str, int k1, unsigned last)
{
- gnutls_buffer_st out_str;
- int k2, k1, result, max_k2;
+ int k2, result, max_k2;
+ int len;
+ uint8_t value[MAX_STRING_LEN];
char tmpbuffer1[ASN1_MAX_NAME_SIZE];
char tmpbuffer2[ASN1_MAX_NAME_SIZE];
char tmpbuffer3[ASN1_MAX_NAME_SIZE];
- uint8_t value[MAX_STRING_LEN];
- gnutls_datum_t td = { NULL, 0 }, tvd = {
- NULL, 0};
const char *ldap_desc;
char oid[MAX_OID_SIZE];
- int len;
+ gnutls_datum_t td = { NULL, 0 };
+ gnutls_datum_t tvd = { NULL, 0 };
- _gnutls_buffer_init(&out_str);
+ /* create a string like "tbsCertList.issuer.rdnSequence.?1"
+ */
+ if (asn1_rdn_name[0] != 0)
+ snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u",
+ asn1_rdn_name, k1);
+ else
+ snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u",
+ k1);
- result = asn1_number_of_elements(asn1_struct, asn1_rdn_name, &k1);
- if (result != ASN1_SUCCESS) {
+ len = sizeof(value) - 1;
+ result =
+ asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
+
+ if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { /* expected */
gnutls_assert();
result = _gnutls_asn2err(result);
goto cleanup;
}
- if (k1 == 0) {
+ k2 = 0;
+
+ result = asn1_number_of_elements(asn1_struct, tmpbuffer1, &max_k2);
+ if (result != ASN1_SUCCESS) {
gnutls_assert();
- result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ result = _gnutls_asn2err(result);
goto cleanup;
}
- while (k1 > 0) {
- /* create a string like "tbsCertList.issuer.rdnSequence.?1"
- */
- if (asn1_rdn_name[0] != 0)
- snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u",
- asn1_rdn_name, k1);
+ do { /* Move to the attibute type and values
+ */
+ k2++;
+
+ if (tmpbuffer1[0] != 0)
+ snprintf(tmpbuffer2, sizeof(tmpbuffer2),
+ "%s.?%u", tmpbuffer1, k2);
else
- snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u",
- k1);
- k1--;
+ snprintf(tmpbuffer2, sizeof(tmpbuffer2),
+ "?%u", k2);
+
+ /* Try to read the RelativeDistinguishedName attributes.
+ */
len = sizeof(value) - 1;
result =
- asn1_read_value(asn1_struct, tmpbuffer1, value, &len);
+ asn1_read_value(asn1_struct, tmpbuffer2, value,
+ &len);
+ if (result == ASN1_ELEMENT_NOT_FOUND)
+ break;
if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { /* expected */
gnutls_assert();
result = _gnutls_asn2err(result);
goto cleanup;
}
- k2 = 0;
+ /* Read the OID
+ */
+ _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
+ tmpbuffer2);
+ _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
+ ".type");
+
+ len = sizeof(oid) - 1;
+ result =
+ asn1_read_value(asn1_struct, tmpbuffer3, oid,
+ &len);
- result = asn1_number_of_elements(asn1_struct, tmpbuffer1, &max_k2);
- if (result != ASN1_SUCCESS) {
+ if (result == ASN1_ELEMENT_NOT_FOUND)
+ break;
+ else if (result != ASN1_SUCCESS) {
gnutls_assert();
result = _gnutls_asn2err(result);
goto cleanup;
}
- do { /* Move to the attibute type and values
- */
- k2++;
-
- if (tmpbuffer1[0] != 0)
- snprintf(tmpbuffer2, sizeof(tmpbuffer2),
- "%s.?%u", tmpbuffer1, k2);
- else
- snprintf(tmpbuffer2, sizeof(tmpbuffer2),
- "?%u", k2);
+ /* Read the Value
+ */
+ _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
+ tmpbuffer2);
+ _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
+ ".value");
- /* Try to read the RelativeDistinguishedName attributes.
- */
+ len = 0;
- len = sizeof(value) - 1;
- result =
- asn1_read_value(asn1_struct, tmpbuffer2, value,
- &len);
+ result =
+ _gnutls_x509_read_value(asn1_struct,
+ tmpbuffer3, &tvd);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+#define STR_APPEND(y) if ((result=_gnutls_buffer_append_str( str, y)) < 0) { \
+ gnutls_assert(); \
+ goto cleanup; \
+}
+#define DATA_APPEND(x,y) if ((result=_gnutls_buffer_append_data( str, x,y)) < 0) { \
+ gnutls_assert(); \
+ goto cleanup; \
+}
+ /* The encodings of adjoining RelativeDistinguishedNames are separated
+ * by a comma character (',' ASCII 44).
+ */
- if (result == ASN1_ELEMENT_NOT_FOUND)
- break;
- if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS) { /* expected */
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
+ ldap_desc =
+ gnutls_x509_dn_oid_name(oid,
+ GNUTLS_X509_DN_OID_RETURN_OID);
- /* Read the OID
- */
- _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
- tmpbuffer2);
- _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
- ".type");
+ STR_APPEND(ldap_desc);
+ STR_APPEND("=");
- len = sizeof(oid) - 1;
- result =
- asn1_read_value(asn1_struct, tmpbuffer3, oid,
- &len);
+ result =
+ _gnutls_x509_dn_to_string(oid, tvd.data,
+ tvd.size, &td);
+ if (result < 0) {
+ gnutls_assert();
+ _gnutls_debug_log
+ ("Cannot parse OID: '%s' with value '%s'\n",
+ oid, _gnutls_bin2hex(tvd.data,
+ tvd.size,
+ tmpbuffer3,
+ sizeof
+ (tmpbuffer3),
+ NULL));
+ goto cleanup;
+ }
- if (result == ASN1_ELEMENT_NOT_FOUND)
- break;
- else if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
+ DATA_APPEND(td.data, td.size);
+ _gnutls_free_datum(&td);
+ _gnutls_free_datum(&tvd);
- /* Read the Value
- */
- _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3),
- tmpbuffer2);
- _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3),
- ".value");
+ /* Where there is a multi-valued RDN, the outputs from adjoining
+ * AttributeTypeAndValues are separated by a plus ('+' ASCII 43)
+ * character.
+ */
+ if (k2 < max_k2) {
+ STR_APPEND("+");
+ } else if (!last) {
+ STR_APPEND(",");
+ }
+ }
+ while (1);
- len = 0;
+ result = 0;
- result =
- _gnutls_x509_read_value(asn1_struct,
- tmpbuffer3, &tvd);
- if (result < 0) {
- gnutls_assert();
- goto cleanup;
- }
-#define STR_APPEND(y) if ((result=_gnutls_buffer_append_str( &out_str, y)) < 0) { \
- gnutls_assert(); \
- goto cleanup; \
-}
-#define DATA_APPEND(x,y) if ((result=_gnutls_buffer_append_data( &out_str, x,y)) < 0) { \
- gnutls_assert(); \
- goto cleanup; \
+ cleanup:
+ _gnutls_free_datum(&td);
+ _gnutls_free_datum(&tvd);
+ return result;
}
- /* The encodings of adjoining RelativeDistinguishedNames are separated
- * by a comma character (',' ASCII 44).
- */
- ldap_desc =
- gnutls_x509_dn_oid_name(oid,
- GNUTLS_X509_DN_OID_RETURN_OID);
+int
+_gnutls_x509_get_dn(ASN1_TYPE asn1_struct,
+ const char *asn1_rdn_name, gnutls_datum_t * dn,
+ unsigned flags)
+{
+ gnutls_buffer_st out_str;
+ int i, k1, result;
- STR_APPEND(ldap_desc);
- STR_APPEND("=");
+ _gnutls_buffer_init(&out_str);
- result =
- _gnutls_x509_dn_to_string(oid, tvd.data,
- tvd.size, &td);
+ result = asn1_number_of_elements(asn1_struct, asn1_rdn_name, &k1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (k1 == 0) {
+ gnutls_assert();
+ result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto cleanup;
+ }
+
+ if (flags & GNUTLS_X509_DN_FLAG_COMPAT) {
+ for (i=0;i<k1;i++) {
+ result = append_elements(asn1_struct, asn1_rdn_name, &out_str, i+1, (i==(k1-1))?1:0);
if (result < 0) {
gnutls_assert();
- _gnutls_debug_log
- ("Cannot parse OID: '%s' with value '%s'\n",
- oid, _gnutls_bin2hex(tvd.data,
- tvd.size,
- tmpbuffer3,
- sizeof
- (tmpbuffer3),
- NULL));
goto cleanup;
}
-
- DATA_APPEND(td.data, td.size);
- _gnutls_free_datum(&td);
- _gnutls_free_datum(&tvd);
-
- /* Where there is a multi-valued RDN, the outputs from adjoining
- * AttributeTypeAndValues are separated by a plus ('+' ASCII 43)
- * character.
- */
- if (k2 < max_k2) {
- STR_APPEND("+");
- } else if (k1 > 0) {
- STR_APPEND(",");
+ }
+ } else {
+ while (k1 > 0) {
+ result = append_elements(asn1_struct, asn1_rdn_name, &out_str, k1, k1==1?1:0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
}
-
+ k1--;
}
- while (1);
}
- result = _gnutls_buffer_to_datum(&out_str, dn, 1);
- if (result < 0)
- gnutls_assert();
-
- goto cleanup1;
+ return _gnutls_buffer_to_datum(&out_str, dn, 1);
- cleanup:
+ cleanup:
_gnutls_buffer_clear(&out_str);
- cleanup1:
- _gnutls_free_datum(&td);
- _gnutls_free_datum(&tvd);
return result;
}
@@ -235,7 +256,7 @@ _gnutls_x509_get_dn(ASN1_TYPE asn1_struct,
int
_gnutls_x509_parse_dn(ASN1_TYPE asn1_struct,
const char *asn1_rdn_name, char *buf,
- size_t * buf_size)
+ size_t * buf_size, unsigned flags)
{
int ret;
gnutls_datum_t dn = {NULL, 0};
@@ -250,7 +271,7 @@ _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct,
else
*buf_size = 0;
- ret = _gnutls_x509_get_dn(asn1_struct, asn1_rdn_name, &dn);
+ ret = _gnutls_x509_get_dn(asn1_struct, asn1_rdn_name, &dn, flags);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -760,6 +781,9 @@ _gnutls_x509_set_dn_oid(ASN1_TYPE asn1_struct,
* name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
* RFC4514.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_rdn_get2().
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
* %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
* updated if the provided buffer is not long enough, otherwise a
@@ -796,7 +820,56 @@ gnutls_x509_rdn_get(const gnutls_datum_t * idn,
return _gnutls_asn2err(result);
}
- result = _gnutls_x509_parse_dn(dn, "rdnSequence", buf, buf_size);
+ result = _gnutls_x509_parse_dn(dn, "rdnSequence", buf, buf_size, GNUTLS_X509_DN_FLAG_COMPAT);
+
+ asn1_delete_structure(&dn);
+ return result;
+
+}
+
+/**
+ * gnutls_x509_rdn_get2:
+ * @idn: should contain a DER encoded RDN sequence
+ * @buf: a pointer to a structure to hold the peer's name
+ * @buf_size: holds the size of @buf
+ * @flags:
+ *
+ * This function will return the name of the given RDN sequence. The
+ * name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as described in
+ * RFC4514.
+ *
+ * When the flag %GNUTLS_X509_DN_FLAG_COMPAT is specified, the output
+ * format will match the format output by previous to 3.5.6 versions of GnuTLS
+ * which was not not fully RFC4514-compliant.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or
+ * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@buf_size is
+ * updated if the provided buffer is not long enough, otherwise a
+ * negative error value.
+ **/
+int
+gnutls_x509_rdn_get2(const gnutls_datum_t * idn,
+ gnutls_datum_t *str, unsigned flags)
+{
+ int result;
+ ASN1_TYPE dn = ASN1_TYPE_EMPTY;
+
+ if ((result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.Name", &dn)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = _asn1_strict_der_decode(&dn, idn->data, idn->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ /* couldn't decode DER */
+ gnutls_assert();
+ asn1_delete_structure(&dn);
+ return _gnutls_asn2err(result);
+ }
+
+ result = _gnutls_x509_get_dn(dn, "rdnSequence", str, flags);
asn1_delete_structure(&dn);
return result;