/* 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_string out_str; int k2, k1, result; char tmpbuffer1[MAX_NAME_SIZE]; char tmpbuffer2[MAX_NAME_SIZE]; char tmpbuffer3[MAX_NAME_SIZE]; opaque value[MAX_STRING_LEN], *value2 = NULL; char *escaped = NULL; const char *ldap_desc; char oid[128]; int len, printable; char *string = NULL; size_t sizeof_string, sizeof_escaped; if (sizeof_buf == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (buf) buf[0] = 0; else *sizeof_buf = 0; _gnutls_string_init (&out_str, gnutls_malloc, gnutls_realloc, gnutls_free); 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_string_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 = oid2ldap_string (oid); printable = _gnutls_x509_oid_data_printable (oid); sizeof_escaped = 2 * len + 1; 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 ("="); if (printable) result = _gnutls_x509_oid_data2string (oid, value2, len, string, &sizeof_string); else result = _gnutls_x509_data2hex (value2, len, string, &sizeof_string); if (result < 0) { gnutls_assert (); _gnutls_x509_log ("Found OID: '%s' with value '%s'\n", oid, _gnutls_bin2hex (value2, len, escaped, sizeof_escaped)); 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) { memcpy (buf, out_str.data, out_str.length); buf[out_str.length] = 0; } *sizeof_buf = out_str.length; result = 0; cleanup: gnutls_free (value2); gnutls_free (string); gnutls_free (escaped); _gnutls_string_clear (&out_str); return result; }
/* This function will convert an attribute value, specified by the OID, * to a string. The result will be a null terminated string. * * res may be null. This will just return the res_size, needed to * hold the string. */ int _gnutls_x509_oid_data2string (const char *oid, void *value, int value_size, char *res, size_t * res_size) { char str[MAX_STRING_LEN], tmpname[128]; const char *ANAME = NULL; int CHOICE = -1, len = -1, result; ASN1_TYPE tmpasn = ASN1_TYPE_EMPTY; char asn1_err[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = ""; if (value == NULL || value_size <= 0 || res_size == NULL) { gnutls_assert (); return GNUTLS_E_INVALID_REQUEST; } if (_gnutls_x509_oid_data_printable (oid) == 0) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } ANAME = _gnutls_x509_oid2asn_string (oid); CHOICE = _gnutls_x509_oid_data_choice (oid); if (ANAME == NULL) { gnutls_assert (); return GNUTLS_E_INTERNAL_ERROR; } if ((result = asn1_create_element (_gnutls_get_pkix (), ANAME, &tmpasn)) != ASN1_SUCCESS) { gnutls_assert (); return _gnutls_asn2err (result); } if ((result = asn1_der_decoding (&tmpasn, value, value_size, asn1_err)) != ASN1_SUCCESS) { gnutls_assert (); _gnutls_debug_log ("asn1_der_decoding: %s:%s\n", str, asn1_err); asn1_delete_structure (&tmpasn); return _gnutls_asn2err (result); } /* If this is a choice then we read the choice. Otherwise it * is the value; */ len = sizeof (str) - 1; if ((result = asn1_read_value (tmpasn, "", str, &len)) != ASN1_SUCCESS) { /* CHOICE */ gnutls_assert (); asn1_delete_structure (&tmpasn); return _gnutls_asn2err (result); } if (CHOICE == 0) { str[len] = 0; /* Refuse to deal with strings containing NULs. */ if (strlen (str) != len) return GNUTLS_E_ASN1_DER_ERROR; if (res) _gnutls_str_cpy (res, *res_size, str); *res_size = len; asn1_delete_structure (&tmpasn); } else { /* CHOICE */ int non_printable = 0, teletex = 0; str[len] = 0; /* Note that we do not support strings other than * UTF-8 (thus ASCII as well). */ if (strcmp (str, "printableString") != 0 && strcmp (str, "ia5String") != 0 && strcmp (str, "utf8String") != 0) { non_printable = 1; } if (strcmp (str, "teletexString") == 0) teletex = 1; _gnutls_str_cpy (tmpname, sizeof (tmpname), str); len = sizeof (str) - 1; if ((result = asn1_read_value (tmpasn, tmpname, str, &len)) != ASN1_SUCCESS) { asn1_delete_structure (&tmpasn); return _gnutls_asn2err (result); } asn1_delete_structure (&tmpasn); if (teletex != 0) { int ascii = 0, i; /* HACK: if the teletex string contains only ascii * characters then treat it as printable. */ for (i = 0; i < len; i++) if (!isascii (str[i])) ascii = 1; if (ascii == 0) non_printable = 0; } if (non_printable == 0) { str[len] = 0; /* Refuse to deal with strings containing NULs. */ if (strlen (str) != len) return GNUTLS_E_ASN1_DER_ERROR; if (res) _gnutls_str_cpy (res, *res_size, str); *res_size = len; } else { result = _gnutls_x509_data2hex (str, len, res, res_size); if (result < 0) { gnutls_assert (); return result; } } } return 0; }
/* 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[MAX_NAME_SIZE]; char tmpbuffer2[MAX_NAME_SIZE]; char tmpbuffer3[MAX_NAME_SIZE]; opaque value[256]; char oid[128]; 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; }