/* * Copyright (C) 2003-2005, 2007-2010, 2012 Free Software Foundation, * Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ #include #include #include #include #include #include #include #include /* This file includes all the required to parse an X.509 Distriguished * Name (you need a parser just to read a name in the X.509 protoocols!!!) */ /* Escapes a string following the rules from RFC4514. */ static char * str_escape (char *str, char *buffer, unsigned int buffer_size) { int str_length, j, i; if (str == NULL || buffer == NULL) return NULL; str_length = MIN (strlen (str), buffer_size - 1); for (i = j = 0; i < str_length; i++) { if (str[i] == ',' || str[i] == '+' || str[i] == '"' || str[i] == '\\' || str[i] == '<' || str[i] == '>' || str[i] == ';') buffer[j++] = '\\'; buffer[j++] = str[i]; } /* null terminate the string */ buffer[j] = 0; return buffer; } /* Parses an X509 DN in the asn1_struct, and puts the output into * the string buf. The output is an LDAP encoded DN. * * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence". * That is to point in the rndSequence. */ int _gnutls_x509_parse_dn (ASN1_TYPE asn1_struct, const char *asn1_rdn_name, char *buf, size_t * sizeof_buf) { gnutls_buffer_st out_str; int k2, k1, result; char tmpbuffer1[ASN1_MAX_NAME_SIZE]; char tmpbuffer2[ASN1_MAX_NAME_SIZE]; char tmpbuffer3[ASN1_MAX_NAME_SIZE]; uint8_t value[MAX_STRING_LEN], *value2 = NULL; char *escaped = NULL; const char *ldap_desc; char oid[MAX_OID_SIZE]; int len, printable; char *string = NULL; size_t sizeof_string, sizeof_escaped; if (sizeof_buf == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (*sizeof_buf > 0 && buf) buf[0] = 0; else *sizeof_buf = 0; _gnutls_buffer_init (&out_str); k1 = 0; do { k1++; /* 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); len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } k2 = 0; 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); /* Try to read the RelativeDistinguishedName attributes. */ len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) break; if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* 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); if (result == ASN1_ELEMENT_NOT_FOUND) break; else if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* Read the Value */ _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2); _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".value"); len = 0; result = asn1_read_value (asn1_struct, tmpbuffer3, NULL, &len); value2 = gnutls_malloc (len); if (value2 == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } result = asn1_read_value (asn1_struct, tmpbuffer3, value2, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } #define STR_APPEND(y) if ((result=_gnutls_buffer_append_str( &out_str, y)) < 0) { \ gnutls_assert(); \ goto cleanup; \ } /* The encodings of adjoining RelativeDistinguishedNames are separated * by a comma character (',' ASCII 44). */ /* Where there is a multi-valued RDN, the outputs from adjoining * AttributeTypeAndValues are separated by a plus ('+' ASCII 43) * character. */ if (k1 != 1) { /* the first time do not append a comma */ if (k2 != 1) { /* adjoining multi-value RDN */ STR_APPEND ("+"); } else { STR_APPEND (","); } } ldap_desc = gnutls_x509_dn_oid_name (oid, GNUTLS_X509_DN_OID_RETURN_OID); printable = _gnutls_x509_oid_data_printable (oid); /* leading #, hex encoded value and terminating NULL */ sizeof_escaped = 2 * len + 2; escaped = gnutls_malloc (sizeof_escaped); if (escaped == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } sizeof_string = 2 * len + 2; /* in case it is not printable */ string = gnutls_malloc (sizeof_string); if (string == NULL) { gnutls_assert (); result = GNUTLS_E_MEMORY_ERROR; goto cleanup; } STR_APPEND (ldap_desc); STR_APPEND ("="); result = 0; if (printable) result = _gnutls_x509_oid_data2string (oid, value2, len, string, &sizeof_string); if (!printable || result < 0) result = _gnutls_x509_data2hex (value2, len, string, &sizeof_string); if (result < 0) { gnutls_assert (); _gnutls_debug_log ("Found OID: '%s' with value '%s'\n", oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped, NULL)); goto cleanup; } STR_APPEND (str_escape (string, escaped, sizeof_escaped)); gnutls_free (string); string = NULL; gnutls_free (escaped); escaped = NULL; gnutls_free (value2); value2 = NULL; } while (1); } while (1); if (out_str.length >= (unsigned int) *sizeof_buf) { gnutls_assert (); *sizeof_buf = out_str.length + 1; result = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } if (buf) { _gnutls_buffer_pop_data (&out_str, buf, sizeof_buf); buf[*sizeof_buf] = 0; } else *sizeof_buf = out_str.length; result = 0; cleanup: gnutls_free (value2); gnutls_free (string); gnutls_free (escaped); _gnutls_buffer_clear (&out_str); return result; } /* Parses an X509 DN in the asn1_struct, and searches for the * given OID in the DN. * * If raw_flag == 0, the output will be encoded in the LDAP way. (#hex for non printable) * Otherwise the raw DER data are returned. * * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence". * That is to point in the rndSequence. * * indx specifies which OID to return. Ie 0 means return the first specified * OID found, 1 the second etc. */ int _gnutls_x509_parse_dn_oid (ASN1_TYPE asn1_struct, const char *asn1_rdn_name, const char *given_oid, int indx, unsigned int raw_flag, void *buf, size_t * sizeof_buf) { int k2, k1, result; char tmpbuffer1[ASN1_MAX_NAME_SIZE]; char tmpbuffer2[ASN1_MAX_NAME_SIZE]; char tmpbuffer3[ASN1_MAX_NAME_SIZE]; uint8_t value[256]; char oid[MAX_OID_SIZE]; int len, printable; int i = 0; char *cbuf = buf; if (cbuf == NULL) *sizeof_buf = 0; else cbuf[0] = 0; k1 = 0; do { k1++; /* 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); len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { gnutls_assert (); break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } k2 = 0; 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); /* Try to read the RelativeDistinguishedName attributes. */ len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* 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); if (result == ASN1_ELEMENT_NOT_FOUND) break; else if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (strcmp (oid, given_oid) == 0 && indx == i++) { /* Found the OID */ /* Read the Value */ _gnutls_str_cpy (tmpbuffer3, sizeof (tmpbuffer3), tmpbuffer2); _gnutls_str_cat (tmpbuffer3, sizeof (tmpbuffer3), ".value"); len = *sizeof_buf; result = asn1_read_value (asn1_struct, tmpbuffer3, buf, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); if (result == ASN1_MEM_ERROR) *sizeof_buf = len; result = _gnutls_asn2err (result); goto cleanup; } if (raw_flag != 0) { if ((unsigned) len > *sizeof_buf) { *sizeof_buf = len; result = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } *sizeof_buf = len; return 0; } else { /* parse data. raw_flag == 0 */ printable = _gnutls_x509_oid_data_printable (oid); if (printable == 1) result = _gnutls_x509_oid_data2string (oid, buf, len, cbuf, sizeof_buf); else result = _gnutls_x509_data2hex (buf, len, cbuf, sizeof_buf); if (result < 0) { gnutls_assert (); goto cleanup; } return 0; } /* raw_flag == 0 */ } } while (1); } while (1); gnutls_assert (); result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; cleanup: return result; } /* Parses an X509 DN in the asn1_struct, and returns the requested * DN OID. * * asn1_rdn_name must be a string in the form "tbsCertificate.issuer.rdnSequence". * That is to point in the rndSequence. * * indx specifies which OID to return. Ie 0 means return the first specified * OID found, 1 the second etc. */ int _gnutls_x509_get_dn_oid (ASN1_TYPE asn1_struct, const char *asn1_rdn_name, int indx, void *_oid, size_t * sizeof_oid) { int k2, k1, result; char tmpbuffer1[ASN1_MAX_NAME_SIZE]; char tmpbuffer2[ASN1_MAX_NAME_SIZE]; char tmpbuffer3[ASN1_MAX_NAME_SIZE]; char value[256]; char oid[MAX_OID_SIZE]; int len; int i = 0; k1 = 0; do { k1++; /* 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); len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer1, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { gnutls_assert (); break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } k2 = 0; 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); /* Try to read the RelativeDistinguishedName attributes. */ len = sizeof (value) - 1; result = asn1_read_value (asn1_struct, tmpbuffer2, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } /* 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); if (result == ASN1_ELEMENT_NOT_FOUND) break; else if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto cleanup; } if (indx == i++) { /* Found the OID */ len = strlen (oid) + 1; if (*sizeof_oid < (unsigned) len) { *sizeof_oid = len; gnutls_assert (); return GNUTLS_E_SHORT_MEMORY_BUFFER; } memcpy (_oid, oid, len); *sizeof_oid = len - 1; return 0; } } while (1); } while (1); gnutls_assert (); result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; cleanup: return result; } /* This will encode and write the AttributeTypeAndValue field. * 'multi' must be (0) if writing an AttributeTypeAndValue, and 1 if Attribute. * In all cases only one value is written. */ int _gnutls_x509_encode_and_write_attribute (const char *given_oid, ASN1_TYPE asn1_struct, const char *where, const void *_data, int sizeof_data, int multi) { const char *val_name; const uint8_t *data = _data; char tmp[128]; ASN1_TYPE c2; int result; /* Find how to encode the data. */ val_name = _gnutls_x509_oid2asn_string (given_oid); if (val_name == NULL) { gnutls_assert (); _gnutls_debug_log ("Cannot find OID: %s\n", given_oid); return GNUTLS_E_X509_UNSUPPORTED_OID; } result = asn1_create_element (_gnutls_get_pkix (), val_name, &c2); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } tmp[0] = 0; if ((result = _gnutls_x509_oid_data_choice (given_oid)) > 0) { const char *string_type; int i; string_type = "printableString"; /* Check if the data is plain ascii, and use * the UTF8 string type if not. */ for (i = 0; i < sizeof_data; i++) { if (!isascii (data[i])) { string_type = "utf8String"; break; } } /* if the type is a CHOICE then write the * type we'll use. */ result = asn1_write_value (c2, "", string_type, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } _gnutls_str_cpy (tmp, sizeof (tmp), string_type); } result = asn1_write_value (c2, tmp, data, sizeof_data); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } /* write the data (value) */ _gnutls_str_cpy (tmp, sizeof (tmp), where); _gnutls_str_cat (tmp, sizeof (tmp), ".value"); if (multi != 0) { /* if not writing an AttributeTypeAndValue, but an Attribute */ _gnutls_str_cat (tmp, sizeof (tmp), "s"); /* values */ result = asn1_write_value (asn1_struct, tmp, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST"); } result = _gnutls_x509_der_encode_and_copy (c2, "", asn1_struct, tmp, 0); if (result < 0) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } /* write the type */ _gnutls_str_cpy (tmp, sizeof (tmp), where); _gnutls_str_cat (tmp, sizeof (tmp), ".type"); result = asn1_write_value (asn1_struct, tmp, given_oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); goto error; } result = 0; error: asn1_delete_structure (&c2); return result; } /* This will write the AttributeTypeAndValue field. The data must be already DER encoded. * 'multi' must be (0) if writing an AttributeTypeAndValue, and 1 if Attribute. * In all cases only one value is written. */ static int _gnutls_x509_write_attribute (const char *given_oid, ASN1_TYPE asn1_struct, const char *where, const void *_data, int sizeof_data) { char tmp[128]; int result; /* write the data (value) */ _gnutls_str_cpy (tmp, sizeof (tmp), where); _gnutls_str_cat (tmp, sizeof (tmp), ".value"); result = asn1_write_value (asn1_struct, tmp, _data, sizeof_data); if (result < 0) { gnutls_assert (); return _gnutls_asn2err (result); } /* write the type */ _gnutls_str_cpy (tmp, sizeof (tmp), where); _gnutls_str_cat (tmp, sizeof (tmp), ".type"); result = asn1_write_value (asn1_struct, tmp, given_oid, 1); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } return 0; } /* Decodes an X.509 Attribute (if multi==1) or an AttributeTypeAndValue * otherwise. * * octet_string should be non (0) if we are to decode octet strings after * decoding. * * The output is allocated and stored in value. */ int _gnutls_x509_decode_and_read_attribute (ASN1_TYPE asn1_struct, const char *where, char *oid, int oid_size, gnutls_datum_t * value, int multi, int octet_string) { char tmpbuffer[128]; int len, result; /* Read the OID */ _gnutls_str_cpy (tmpbuffer, sizeof (tmpbuffer), where); _gnutls_str_cat (tmpbuffer, sizeof (tmpbuffer), ".type"); len = oid_size - 1; result = asn1_read_value (asn1_struct, tmpbuffer, oid, &len); if (result != ASN1_SUCCESS) { gnutls_assert (); result = _gnutls_asn2err (result); return result; } /* Read the Value */ _gnutls_str_cpy (tmpbuffer, sizeof (tmpbuffer), where); _gnutls_str_cat (tmpbuffer, sizeof (tmpbuffer), ".value"); if (multi) _gnutls_str_cat (tmpbuffer, sizeof (tmpbuffer), "s.?1"); /* .values.?1 */ result = _gnutls_x509_read_value (asn1_struct, tmpbuffer, value, octet_string); if (result < 0) { gnutls_assert (); return result; } return 0; } /* Sets an X509 DN in the asn1_struct, and puts the given OID in the DN. * The input is assumed to be raw data. * * asn1_rdn_name must be a string in the form "tbsCertificate.issuer". * That is to point before the rndSequence. * */ int _gnutls_x509_set_dn_oid (ASN1_TYPE asn1_struct, const char *asn1_name, const char *given_oid, int raw_flag, const char *name, int sizeof_name) { int result; char tmp[ASN1_MAX_NAME_SIZE], asn1_rdn_name[ASN1_MAX_NAME_SIZE]; if (sizeof_name == 0 || name == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } /* create the rdnSequence */ result = asn1_write_value (asn1_struct, asn1_name, "rdnSequence", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } _gnutls_str_cpy (asn1_rdn_name, sizeof (asn1_rdn_name), asn1_name); _gnutls_str_cat (asn1_rdn_name, sizeof (asn1_rdn_name), ".rdnSequence"); /* create a new element */ result = asn1_write_value (asn1_struct, asn1_rdn_name, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } _gnutls_str_cpy (tmp, sizeof (tmp), asn1_rdn_name); _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST"); /* create the set with only one element */ result = asn1_write_value (asn1_struct, tmp, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } /* Encode and write the data */ _gnutls_str_cpy (tmp, sizeof (tmp), asn1_rdn_name); _gnutls_str_cat (tmp, sizeof (tmp), ".?LAST.?LAST"); if (!raw_flag) { result = _gnutls_x509_encode_and_write_attribute (given_oid, asn1_struct, tmp, name, sizeof_name, 0); } else { result = _gnutls_x509_write_attribute (given_oid, asn1_struct, tmp, name, sizeof_name); } if (result < 0) { gnutls_assert (); return result; } return 0; } /** * gnutls_x509_dn_init: * @dn: the object to be initialized * * This function initializes a #gnutls_x509_dn_t structure. * * The object returned must be deallocated using * gnutls_x509_dn_deinit(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.4.0 **/ int gnutls_x509_dn_init (gnutls_x509_dn_t * dn) { int result; ASN1_TYPE tmpdn = ASN1_TYPE_EMPTY; if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.Name", &tmpdn)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } *dn = tmpdn; return 0; } /** * gnutls_x509_dn_import: * @dn: the structure that will hold the imported DN * @data: should contain a DER encoded RDN sequence * * This function parses an RDN sequence and stores the result to a * #gnutls_x509_dn_t structure. The structure must have been initialized * with gnutls_x509_dn_init(). You may use gnutls_x509_dn_get_rdn_ava() to * decode the DN. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 2.4.0 **/ int gnutls_x509_dn_import (gnutls_x509_dn_t dn, const gnutls_datum_t * data) { int result; char err[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; result = asn1_der_decoding ((ASN1_TYPE *) & dn, data->data, data->size, err); if (result != ASN1_SUCCESS) { /* couldn't decode DER */ _gnutls_debug_log ("ASN.1 Decoding error: %s\n", err); gnutls_assert (); return _gnutls_asn2err (result); } return 0; } /** * gnutls_x509_dn_deinit: * @dn: a DN uint8_t object pointer. * * This function deallocates the DN object as returned by * gnutls_x509_dn_import(). * * Since: 2.4.0 **/ void gnutls_x509_dn_deinit (gnutls_x509_dn_t dn) { asn1_delete_structure ((ASN1_TYPE *) & dn); } /** * gnutls_x509_rdn_get: * @idn: should contain a DER encoded RDN sequence * @buf: a pointer to a structure to hold the peer's name * @sizeof_buf: holds the size of @buf * * 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. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@sizeof_buf is * updated if the provided buffer is not long enough, otherwise a * negative error value. **/ int gnutls_x509_rdn_get (const gnutls_datum_t * idn, char *buf, size_t * sizeof_buf) { int result; ASN1_TYPE dn = ASN1_TYPE_EMPTY; if (sizeof_buf == 0) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (buf) buf[0] = 0; if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.Name", &dn)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_der_decoding (&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_parse_dn (dn, "rdnSequence", buf, sizeof_buf); asn1_delete_structure (&dn); return result; } /** * gnutls_x509_rdn_get_by_oid: * @idn: should contain a DER encoded RDN sequence * @oid: an Object Identifier * @indx: In case multiple same OIDs exist in the RDN indicates which * to send. Use 0 for the first one. * @raw_flag: If non (0) then the raw DER data are returned. * @buf: a pointer to a structure to hold the peer's name * @sizeof_buf: holds the size of @buf * * This function will return the name of the given Object identifier, * of the RDN sequence. The name will be encoded using the rules * from RFC4514. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@sizeof_buf is * updated if the provided buffer is not long enough, otherwise a * negative error value. **/ int gnutls_x509_rdn_get_by_oid (const gnutls_datum_t * idn, const char *oid, int indx, unsigned int raw_flag, void *buf, size_t * sizeof_buf) { int result; ASN1_TYPE dn = ASN1_TYPE_EMPTY; if (sizeof_buf == 0) { return GNUTLS_E_INVALID_REQUEST; } if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.Name", &dn)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_der_decoding (&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_parse_dn_oid (dn, "rdnSequence", oid, indx, raw_flag, buf, sizeof_buf); asn1_delete_structure (&dn); return result; } /** * gnutls_x509_rdn_get_oid: * @idn: should contain a DER encoded RDN sequence * @indx: Indicates which OID to return. Use 0 for the first one. * @buf: a pointer to a structure to hold the peer's name OID * @sizeof_buf: holds the size of @buf * * This function will return the specified Object identifier, of the * RDN sequence. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or * %GNUTLS_E_SHORT_MEMORY_BUFFER is returned and *@sizeof_buf is * updated if the provided buffer is not long enough, otherwise a * negative error value. * * Since: 2.4.0 **/ int gnutls_x509_rdn_get_oid (const gnutls_datum_t * idn, int indx, void *buf, size_t * sizeof_buf) { int result; ASN1_TYPE dn = ASN1_TYPE_EMPTY; if (sizeof_buf == 0) { return GNUTLS_E_INVALID_REQUEST; } if ((result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.Name", &dn)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } result = asn1_der_decoding (&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_oid (dn, "rdnSequence", indx, buf, sizeof_buf); asn1_delete_structure (&dn); return result; } /* * Compares the DER encoded part of a DN. * * FIXME: use a real DN comparison algorithm. * * Returns 1 if the DN's match and (0) if they don't match. Otherwise * a negative error code is returned to indicate error. */ int _gnutls_x509_compare_raw_dn (const gnutls_datum_t * dn1, const gnutls_datum_t * dn2) { if (dn1->size != dn2->size) { gnutls_assert (); return 0; } if (memcmp (dn1->data, dn2->data, dn2->size) != 0) { gnutls_assert (); return 0; } return 1; /* they match */ } /** * gnutls_x509_dn_export: * @dn: Holds the uint8_t DN object * @format: the format of output params. One of PEM or DER. * @output_data: will contain a DN PEM or DER encoded * @output_data_size: holds the size of output_data (and will be * replaced by the actual size of parameters) * * This function will export the DN to DER or PEM format. * * If the buffer provided is not long enough to hold the output, then * *@output_data_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER * will be returned. * * If the structure is PEM encoded, it will have a header * of "BEGIN NAME". * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_dn_export (gnutls_x509_dn_t dn, gnutls_x509_crt_fmt_t format, void *output_data, size_t * output_data_size) { ASN1_TYPE asn1 = dn; if (asn1 == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } return _gnutls_x509_export_int_named (asn1, "rdnSequence", format, "NAME", output_data, output_data_size); }