summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-11 16:20:01 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-14 13:34:51 +0100
commit70bf8475bb0ab178fe36ee4c601a6cfec8e70a3f (patch)
treef9971b47b9a1ae80832e446dd8ebb61239e9c7e3
parent19f6dc899b3062631eed162f0132f64bc3773282 (diff)
downloadgnutls-70bf8475bb0ab178fe36ee4c601a6cfec8e70a3f.tar.gz
Introduced new functions to allow multiple DN parsing modes
The old DN parsing functions are changed to return the original non-fully compliant with RFC4514 string format, while the new ones return the compliant string by default. This allows applications which relied on the previous format to continue functioning without changes.
-rw-r--r--lib/includes/gnutls/ocsp.h3
-rw-r--r--lib/includes/gnutls/x509.h17
-rw-r--r--lib/libgnutls.map7
-rw-r--r--lib/x509/crl.c47
-rw-r--r--lib/x509/crq.c42
-rw-r--r--lib/x509/dn.c341
-rw-r--r--lib/x509/ocsp.c76
-rw-r--r--lib/x509/x509.c87
-rw-r--r--lib/x509/x509_dn.c33
-rw-r--r--lib/x509/x509_int.h6
10 files changed, 483 insertions, 176 deletions
diff --git a/lib/includes/gnutls/ocsp.h b/lib/includes/gnutls/ocsp.h
index 1a96ce8a29..8ade965dc0 100644
--- a/lib/includes/gnutls/ocsp.h
+++ b/lib/includes/gnutls/ocsp.h
@@ -211,6 +211,9 @@ int gnutls_ocsp_resp_get_response(gnutls_ocsp_resp_t resp,
int gnutls_ocsp_resp_get_version(gnutls_ocsp_resp_t resp);
int gnutls_ocsp_resp_get_responder(gnutls_ocsp_resp_t resp,
gnutls_datum_t * dn);
+int gnutls_ocsp_resp_get_responder2(gnutls_ocsp_resp_t resp,
+ gnutls_datum_t * dn,
+ unsigned flags);
/* the raw key ID of the responder */
#define GNUTLS_OCSP_RESP_ID_KEY 1
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index f665c34eb2..249b22bb4f 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -171,6 +171,8 @@ int gnutls_x509_crt_get_issuer_dn(gnutls_x509_crt_t cert,
char *buf, size_t * buf_size);
int gnutls_x509_crt_get_issuer_dn2(gnutls_x509_crt_t cert,
gnutls_datum_t * dn);
+int gnutls_x509_crt_get_issuer_dn3(gnutls_x509_crt_t cert,
+ gnutls_datum_t * dn, unsigned flags);
int gnutls_x509_crt_get_issuer_dn_oid(gnutls_x509_crt_t cert,
unsigned indx, void *oid,
size_t * oid_size);
@@ -178,9 +180,12 @@ int gnutls_x509_crt_get_issuer_dn_by_oid(gnutls_x509_crt_t cert,
const char *oid, unsigned indx,
unsigned int raw_flag,
void *buf, size_t * buf_size);
+
int gnutls_x509_crt_get_dn(gnutls_x509_crt_t cert, char *buf,
size_t * buf_size);
int gnutls_x509_crt_get_dn2(gnutls_x509_crt_t cert, gnutls_datum_t * dn);
+int gnutls_x509_crt_get_dn3(gnutls_x509_crt_t cert, gnutls_datum_t * dn, unsigned flags);
+
int gnutls_x509_crt_get_dn_oid(gnutls_x509_crt_t cert, unsigned indx,
void *oid, size_t * oid_size);
int gnutls_x509_crt_get_dn_by_oid(gnutls_x509_crt_t cert,
@@ -663,6 +668,10 @@ int gnutls_x509_crt_get_raw_dn(gnutls_x509_crt_t cert,
*/
int gnutls_x509_rdn_get(const gnutls_datum_t * idn,
char *buf, size_t * sizeof_buf);
+int
+gnutls_x509_rdn_get2(const gnutls_datum_t * idn,
+ gnutls_datum_t *str, unsigned flags);
+
int gnutls_x509_rdn_get_oid(const gnutls_datum_t * idn,
unsigned indx, void *buf, size_t * sizeof_buf);
@@ -687,6 +696,10 @@ int gnutls_x509_dn_get_rdn_ava(gnutls_x509_dn_t dn, int irdn,
int iava, gnutls_x509_ava_st * ava);
int gnutls_x509_dn_get_str(gnutls_x509_dn_t dn, gnutls_datum_t *str);
+
+#define GNUTLS_X509_DN_FLAG_COMPAT 1
+int gnutls_x509_dn_get_str2(gnutls_x509_dn_t dn, gnutls_datum_t *str, unsigned flags);
+
int
gnutls_x509_dn_set_str(gnutls_x509_dn_t dn, const char *str, const char **err);
@@ -728,6 +741,9 @@ int gnutls_x509_crl_get_issuer_dn(gnutls_x509_crl_t crl,
char *buf, size_t * sizeof_buf);
int gnutls_x509_crl_get_issuer_dn2(gnutls_x509_crl_t crl,
gnutls_datum_t * dn);
+int gnutls_x509_crl_get_issuer_dn3(gnutls_x509_crl_t crl,
+ gnutls_datum_t * dn, unsigned flags);
+
int gnutls_x509_crl_get_issuer_dn_by_oid(gnutls_x509_crl_t crl,
const char *oid, unsigned indx,
unsigned int raw_flag,
@@ -1231,6 +1247,7 @@ int gnutls_x509_crq_get_private_key_usage_period(gnutls_x509_crq_t
int gnutls_x509_crq_get_dn(gnutls_x509_crq_t crq, char *buf,
size_t * sizeof_buf);
int gnutls_x509_crq_get_dn2(gnutls_x509_crq_t crq, gnutls_datum_t * dn);
+int gnutls_x509_crq_get_dn3(gnutls_x509_crq_t crq, gnutls_datum_t * dn, unsigned flags);
int gnutls_x509_crq_get_dn_oid(gnutls_x509_crq_t crq, unsigned indx,
void *oid, size_t * sizeof_oid);
int gnutls_x509_crq_get_dn_by_oid(gnutls_x509_crq_t crq,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index c0186f5524..9b947baac6 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1124,6 +1124,13 @@ GNUTLS_3_4
gnutls_anon_set_server_known_dh_params;
gnutls_psk_set_server_known_dh_params;
gnutls_x509_crt_check_key_purpose;
+ gnutls_ocsp_resp_get_responder2;
+ gnutls_x509_crt_get_issuer_dn3;
+ gnutls_x509_crt_get_dn3;
+ gnutls_x509_rdn_get2;
+ gnutls_x509_dn_get_str2;
+ gnutls_x509_crl_get_issuer_dn3;
+ gnutls_x509_crq_get_dn3;
local:
*;
};
diff --git a/lib/x509/crl.c b/lib/x509/crl.c
index 5f0abe301e..036703a1bc 100644
--- a/lib/x509/crl.c
+++ b/lib/x509/crl.c
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2003-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2003-2016 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2016 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -194,6 +195,9 @@ gnutls_x509_crl_import(gnutls_x509_crl_t crl,
*
* If buf is %NULL then only the size will be filled.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crl_get_issuer_dn3().
+ *
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is
* not long enough, and in that case the sizeof_buf will be updated
* with the required size, and 0 on success.
@@ -210,7 +214,7 @@ gnutls_x509_crl_get_issuer_dn(const gnutls_x509_crl_t crl, char *buf,
return _gnutls_x509_parse_dn(crl->crl,
"tbsCertList.issuer.rdnSequence",
- buf, sizeof_buf);
+ buf, sizeof_buf, GNUTLS_X509_DN_FLAG_COMPAT);
}
/**
@@ -303,6 +307,9 @@ gnutls_x509_crl_get_dn_oid(gnutls_x509_crl_t crl,
* described in RFC4514. The output string will be ASCII or UTF-8
* encoded, depending on the certificate data.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crl_get_issuer_dn3().
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
*
@@ -317,7 +324,41 @@ gnutls_x509_crl_get_issuer_dn2(gnutls_x509_crl_t crl, gnutls_datum_t * dn)
}
return _gnutls_x509_get_dn(crl->crl,
- "tbsCertList.issuer.rdnSequence", dn);
+ "tbsCertList.issuer.rdnSequence",
+ dn, GNUTLS_X509_DN_FLAG_COMPAT);
+}
+
+/**
+ * gnutls_x509_crl_get_issuer_dn3:
+ * @crl: should contain a #gnutls_x509_crl_t type
+ * @dn: a pointer to a structure to hold the name
+ * @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
+ *
+ * This function will allocate buffer and copy the name of the CRL issuer.
+ * The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
+ * described in RFC4514. The output string will be ASCII or UTF-8
+ * encoded, depending on the certificate data.
+ *
+ * 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, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.7
+ **/
+int
+gnutls_x509_crl_get_issuer_dn3(gnutls_x509_crl_t crl, gnutls_datum_t * dn, unsigned flags)
+{
+ if (crl == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return _gnutls_x509_get_dn(crl->crl,
+ "tbsCertList.issuer.rdnSequence",
+ dn, flags);
}
/**
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index 6a9cccaa5e..50c3e632f1 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -255,6 +255,9 @@ gnutls_x509_crq_get_private_key_usage_period(gnutls_x509_crq_t crq,
* @buf will be ASCII or UTF-8 encoded, depending on the certificate
* data.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crq_get_dn3().
+ *
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the *@buf_size will be updated with
* the required size. On success 0 is returned.
@@ -269,7 +272,7 @@ gnutls_x509_crq_get_dn(gnutls_x509_crq_t crq, char *buf, size_t * buf_size)
return _gnutls_x509_parse_dn(crq->crq,
"certificationRequestInfo.subject.rdnSequence",
- buf, buf_size);
+ buf, buf_size, GNUTLS_X509_DN_FLAG_COMPAT);
}
/**
@@ -282,6 +285,9 @@ gnutls_x509_crq_get_dn(gnutls_x509_crq_t crq, char *buf, size_t * buf_size)
* described in RFC4514. The output string will be ASCII or UTF-8
* encoded, depending on the certificate data.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crq_get_dn3().
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value. and a negative error code on error.
*
@@ -296,7 +302,39 @@ int gnutls_x509_crq_get_dn2(gnutls_x509_crq_t crq, gnutls_datum_t * dn)
return _gnutls_x509_get_dn(crq->crq,
"certificationRequestInfo.subject.rdnSequence",
- dn);
+ dn, GNUTLS_X509_DN_FLAG_COMPAT);
+}
+
+/**
+ * gnutls_x509_crq_get_dn3:
+ * @crq: should contain a #gnutls_x509_crq_t type
+ * @dn: a pointer to a structure to hold the name
+ * @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
+ *
+ * This function will allocate buffer and copy the name of the Certificate
+ * request. The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
+ * described in RFC4514. The output string will be ASCII or UTF-8
+ * encoded, depending on the certificate data.
+ *
+ * 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, otherwise a
+ * negative error value. and a negative error code on error.
+ *
+ * Since: 3.5.7
+ **/
+int gnutls_x509_crq_get_dn3(gnutls_x509_crq_t crq, gnutls_datum_t * dn, unsigned flags)
+{
+ if (crq == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return _gnutls_x509_get_dn(crq->crq,
+ "certificationRequestInfo.subject.rdnSequence",
+ dn, flags);
}
/**
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;
diff --git a/lib/x509/ocsp.c b/lib/x509/ocsp.c
index eb41fcb295..92f037029d 100644
--- a/lib/x509/ocsp.c
+++ b/lib/x509/ocsp.c
@@ -1103,16 +1103,58 @@ int gnutls_ocsp_resp_get_version(gnutls_ocsp_resp_t resp)
* The caller needs to deallocate memory by calling gnutls_free() on
* @dn->data.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_ocsp_resp_get_responder2().
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
- * negative error code is returned.
+ * negative error code is returned. When no data exist it will
+ * return success and set @dn elements to zero.
**/
int
gnutls_ocsp_resp_get_responder(gnutls_ocsp_resp_t resp,
gnutls_datum_t * dn)
{
int ret;
- size_t l = 0;
+ ret = gnutls_ocsp_resp_get_responder2(resp, dn, GNUTLS_X509_DN_FLAG_COMPAT);
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ dn->data = NULL;
+ dn->size = 0;
+ return 0; /* for backwards compatibility */
+ }
+
+ return ret;
+}
+
+/**
+ * gnutls_ocsp_resp_get_responder2:
+ * @resp: should contain a #gnutls_ocsp_resp_t type
+ * @dn: newly allocated buffer with name
+ * @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
+ *
+ * This function will extract the name of the Basic OCSP Response in
+ * the provided buffer. The name will be in the form
+ * "C=xxxx,O=yyyy,CN=zzzz" as described in RFC2253. The output string
+ * will be ASCII or UTF-8 encoded, depending on the certificate data.
+ *
+ * If the responder ID is not a name but a hash, this function
+ * will return zero and the @dn elements will be set to %NULL.
+ *
+ * The caller needs to deallocate memory by calling gnutls_free() on
+ * @dn->data.
+ *
+ * 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, otherwise a
+ * negative error code is returned. When no data exist it will return
+ * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.
+ **/
+int
+gnutls_ocsp_resp_get_responder2(gnutls_ocsp_resp_t resp,
+ gnutls_datum_t * dn, unsigned flags)
+{
if (resp == NULL || dn == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
@@ -1121,33 +1163,9 @@ gnutls_ocsp_resp_get_responder(gnutls_ocsp_resp_t resp,
dn->data = NULL;
dn->size = 0;
- ret = _gnutls_x509_parse_dn
- (resp->basicresp, "tbsResponseData.responderID.byName",
- NULL, &l);
- if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
- if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
- return 0; /* for backwards compatibility */
- gnutls_assert();
- return ret;
- }
-
- dn->data = gnutls_malloc(l);
- if (dn->data == NULL) {
- gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
- }
-
- ret = _gnutls_x509_parse_dn
- (resp->basicresp, "tbsResponseData.responderID.byName",
- (char *) dn->data, &l);
- if (ret != GNUTLS_E_SUCCESS) {
- gnutls_assert();
- return ret;
- }
-
- dn->size = l;
-
- return GNUTLS_E_SUCCESS;
+ return _gnutls_x509_get_dn(resp->basicresp,
+ "tbsResponseData.responderID.byName",
+ dn, flags);
}
/**
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index a9adff2f4a..043d38b479 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -482,6 +482,9 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert,
*
* If @buf is null then only the size will be filled.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crt_get_issuer_dn3().
+ *
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the @buf_size will be updated
* with the required size. %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE if
@@ -498,7 +501,7 @@ gnutls_x509_crt_get_issuer_dn(gnutls_x509_crt_t cert, char *buf,
return _gnutls_x509_parse_dn(cert->cert,
"tbsCertificate.issuer.rdnSequence",
- buf, buf_size);
+ buf, buf_size, GNUTLS_X509_DN_FLAG_COMPAT);
}
/**
@@ -511,6 +514,9 @@ gnutls_x509_crt_get_issuer_dn(gnutls_x509_crt_t cert, char *buf,
* described in RFC4514. The output string will be ASCII or UTF-8
* encoded, depending on the certificate data.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crt_get_issuer_dn3().
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
*
@@ -526,7 +532,40 @@ gnutls_x509_crt_get_issuer_dn2(gnutls_x509_crt_t cert, gnutls_datum_t * dn)
return _gnutls_x509_get_dn(cert->cert,
"tbsCertificate.issuer.rdnSequence",
- dn);
+ dn, GNUTLS_X509_DN_FLAG_COMPAT);
+}
+
+/**
+ * gnutls_x509_crt_get_issuer_dn3:
+ * @cert: should contain a #gnutls_x509_crt_t type
+ * @dn: a pointer to a structure to hold the name
+ * @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
+ *
+ * This function will allocate buffer and copy the name of issuer of the Certificate.
+ * The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
+ * described in RFC4514. The output string will be ASCII or UTF-8
+ * encoded, depending on the certificate data.
+ *
+ * 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, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.7
+ **/
+int
+gnutls_x509_crt_get_issuer_dn3(gnutls_x509_crt_t cert, gnutls_datum_t *dn, unsigned flags)
+{
+ if (cert == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return _gnutls_x509_get_dn(cert->cert,
+ "tbsCertificate.issuer.rdnSequence",
+ dn, flags);
}
/**
@@ -627,6 +666,9 @@ gnutls_x509_crt_get_issuer_dn_oid(gnutls_x509_crt_t cert,
*
* If @buf is null then only the size will be filled.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crt_get_dn3().
+ *
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the @buf_size will be updated
* with the required size. %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE if
@@ -643,7 +685,7 @@ gnutls_x509_crt_get_dn(gnutls_x509_crt_t cert, char *buf,
return _gnutls_x509_parse_dn(cert->cert,
"tbsCertificate.subject.rdnSequence",
- buf, buf_size);
+ buf, buf_size, GNUTLS_X509_DN_FLAG_COMPAT);
}
/**
@@ -656,6 +698,9 @@ gnutls_x509_crt_get_dn(gnutls_x509_crt_t cert, char *buf,
* described in RFC4514. The output string will be ASCII or UTF-8
* encoded, depending on the certificate data.
*
+ * This function does not output a fully RFC4514 compliant string, if
+ * that is required see gnutls_x509_crt_get_dn3().
+ *
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
*
@@ -670,7 +715,39 @@ int gnutls_x509_crt_get_dn2(gnutls_x509_crt_t cert, gnutls_datum_t * dn)
return _gnutls_x509_get_dn(cert->cert,
"tbsCertificate.subject.rdnSequence",
- dn);
+ dn, GNUTLS_X509_DN_FLAG_COMPAT);
+}
+
+/**
+ * gnutls_x509_crt_get_dn3:
+ * @cert: should contain a #gnutls_x509_crt_t type
+ * @dn: a pointer to a structure to hold the name
+ * @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
+ *
+ * This function will allocate buffer and copy the name of the Certificate.
+ * The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
+ * described in RFC4514. The output string will be ASCII or UTF-8
+ * encoded, depending on the certificate data.
+ *
+ * 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, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.7
+ **/
+int gnutls_x509_crt_get_dn3(gnutls_x509_crt_t cert, gnutls_datum_t *dn, unsigned flags)
+{
+ if (cert == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return _gnutls_x509_get_dn(cert->cert,
+ "tbsCertificate.subject.rdnSequence",
+ dn, flags);
}
/**
@@ -1461,7 +1538,7 @@ _gnutls_parse_general_name2(ASN1_TYPE src, const char *src_name,
}
} else if (type == GNUTLS_SAN_DN) {
_gnutls_str_cat(nptr, sizeof(nptr), ".directoryName");
- ret = _gnutls_x509_get_dn(src, nptr, dname);
+ ret = _gnutls_x509_get_dn(src, nptr, dname, 0);
if (ret < 0) {
gnutls_assert();
goto cleanup;
diff --git a/lib/x509/x509_dn.c b/lib/x509/x509_dn.c
index a64ca3ed7f..8936a23d08 100644
--- a/lib/x509/x509_dn.c
+++ b/lib/x509/x509_dn.c
@@ -662,5 +662,36 @@ gnutls_x509_dn_get_str(gnutls_x509_dn_t dn, gnutls_datum_t *str)
return GNUTLS_E_INVALID_REQUEST;
}
- return _gnutls_x509_get_dn(dn->asn, "rdnSequence", str);
+ return _gnutls_x509_get_dn(dn->asn, "rdnSequence", str, GNUTLS_X509_DN_FLAG_COMPAT);
+}
+
+/**
+ * gnutls_x509_dn_get_str:
+ * @dn: a pointer to DN
+ * @str: a datum that will hold the name
+ * @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
+ *
+ * This function will allocate buffer and copy the name in the provided DN.
+ * The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
+ * described in RFC4514. The output string will be ASCII or UTF-8
+ * encoded, depending on the certificate data.
+ *
+ * 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, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.7
+ **/
+int
+gnutls_x509_dn_get_str2(gnutls_x509_dn_t dn, gnutls_datum_t *str, unsigned flags)
+{
+ if (dn == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ return _gnutls_x509_get_dn(dn->asn, "rdnSequence", str, flags);
}
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 25e013f2fb..4fe0e3dc2a 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -165,11 +165,13 @@ int _gnutls_x509_pkix_sign(ASN1_TYPE src, const char *src_name,
int _gnutls_x509_parse_dn(ASN1_TYPE asn1_struct,
const char *asn1_rdn_name, char *buf,
- size_t * sizeof_buf);
+ size_t * sizeof_buf,
+ unsigned flags);
int
_gnutls_x509_get_dn(ASN1_TYPE asn1_struct,
- const char *asn1_rdn_name, gnutls_datum_t * dn);
+ const char *asn1_rdn_name, gnutls_datum_t * dn,
+ unsigned flags);
int
_gnutls_x509_parse_dn_oid(ASN1_TYPE asn1_struct,