From 70bf8475bb0ab178fe36ee4c601a6cfec8e70a3f Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 11 Nov 2016 16:20:01 +0100 Subject: 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. --- lib/includes/gnutls/ocsp.h | 3 + lib/includes/gnutls/x509.h | 17 +++ lib/libgnutls.map | 7 + lib/x509/crl.c | 47 ++++++- lib/x509/crq.c | 42 +++++- lib/x509/dn.c | 341 +++++++++++++++++++++++++++------------------ lib/x509/ocsp.c | 76 ++++++---- lib/x509/x509.c | 87 +++++++++++- lib/x509/x509_dn.c | 33 ++++- lib/x509/x509_int.h | 6 +- 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 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, -- cgit v1.2.1