|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* Copyright (C) 2013-2016 Nikos Mavrogiannopoulos
|
|
Packit |
549fdc |
* Copyright (C) 2016 Red Hat, Inc.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This file is part of GnuTLS.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
549fdc |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
549fdc |
* the License, or (at your option) any later version.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
549fdc |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
549fdc |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
549fdc |
* Lesser General Public License for more details.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* This file contains functions to handle X.509 certificate generation.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#include "gnutls_int.h"
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#include <datum.h>
|
|
Packit |
549fdc |
#include <global.h>
|
|
Packit |
549fdc |
#include "errors.h"
|
|
Packit |
549fdc |
#include <common.h>
|
|
Packit |
549fdc |
#include <x509.h>
|
|
Packit |
549fdc |
#include <x509_b64.h>
|
|
Packit |
549fdc |
#include <c-ctype.h>
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
typedef int (*set_dn_func) (void *, const char *oid, unsigned int raw_flag,
|
|
Packit |
549fdc |
const void *name, unsigned int name_size);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static
|
|
Packit |
549fdc |
int dn_attr_crt_set(set_dn_func f, void *crt, const gnutls_datum_t * name,
|
|
Packit |
549fdc |
const gnutls_datum_t * val, unsigned is_raw)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
char _oid[MAX_OID_SIZE];
|
|
Packit |
549fdc |
gnutls_datum_t tmp;
|
|
Packit |
549fdc |
const char *oid;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
unsigned i,j;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (name->size == 0 || val->size == 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (c_isdigit(name->data[0]) != 0) {
|
|
Packit |
549fdc |
if (name->size >= sizeof(_oid))
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
memcpy(_oid, name->data, name->size);
|
|
Packit |
549fdc |
_oid[name->size] = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
oid = _oid;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (gnutls_x509_dn_oid_known(oid) == 0 && !is_raw) {
|
|
Packit |
549fdc |
_gnutls_debug_log("Unknown OID: '%s'\n", oid);
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
oid =
|
|
Packit |
549fdc |
_gnutls_ldap_string_to_oid((char *) name->data,
|
|
Packit |
549fdc |
name->size);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (oid == NULL) {
|
|
Packit |
549fdc |
_gnutls_debug_log("Unknown DN attribute: '%.*s'\n",
|
|
Packit |
549fdc |
(int) name->size, name->data);
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (is_raw) {
|
|
Packit |
549fdc |
gnutls_datum_t hex = {val->data+1, val->size-1};
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_hex_decode2(&hex, &tmp);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
tmp.size = val->size;
|
|
Packit |
549fdc |
tmp.data = gnutls_malloc(tmp.size+1);
|
|
Packit |
549fdc |
if (tmp.data == NULL) {
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* unescape */
|
|
Packit |
549fdc |
for (j=i=0;i
|
|
Packit |
549fdc |
if (1+j!=val->size && val->data[j] == '\\') {
|
|
Packit |
549fdc |
if (val->data[j+1] == ',' || val->data[j+1] == '#' ||
|
|
Packit |
549fdc |
val->data[j+1] == ' ' || val->data[j+1] == '+' ||
|
|
Packit |
549fdc |
val->data[j+1] == '"' || val->data[j+1] == '<' ||
|
|
Packit |
549fdc |
val->data[j+1] == '>' || val->data[j+1] == ';' ||
|
|
Packit |
549fdc |
val->data[j+1] == '\\' || val->data[j+1] == '=') {
|
|
Packit |
549fdc |
tmp.data[i] = val->data[j+1];
|
|
Packit |
549fdc |
j+=2;
|
|
Packit |
549fdc |
tmp.size--;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
tmp.data[i] = val->data[j++];
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
tmp.data[tmp.size] = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = f(crt, oid, is_raw, tmp.data, tmp.size);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = 0;
|
|
Packit |
549fdc |
fail:
|
|
Packit |
549fdc |
gnutls_free(tmp.data);
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static int read_attr_and_val(const char **ptr,
|
|
Packit |
549fdc |
gnutls_datum_t *name, gnutls_datum_t *val,
|
|
Packit |
549fdc |
unsigned *is_raw)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
const unsigned char *p = (void *) *ptr;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
*is_raw = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* skip any space */
|
|
Packit |
549fdc |
while (c_isspace(*p))
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Read the name */
|
|
Packit |
549fdc |
name->data = (void *) p;
|
|
Packit |
549fdc |
while (*p != '=' && *p != 0 && !c_isspace(*p))
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
name->size = p - name->data;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* skip any space */
|
|
Packit |
549fdc |
while (c_isspace(*p))
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (*p != '=')
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
while (c_isspace(*p))
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (*p == '#') {
|
|
Packit |
549fdc |
*is_raw = 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Read value */
|
|
Packit |
549fdc |
val->data = (void *) p;
|
|
Packit |
549fdc |
while (*p != 0 && (*p != ',' || (*p == ',' && *(p - 1) == '\\'))
|
|
Packit |
549fdc |
&& *p != '\n') {
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
val->size = p - (val->data);
|
|
Packit |
549fdc |
*ptr = (void*)p;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
p = val->data;
|
|
Packit |
549fdc |
/* check for unescaped '+' - we do not support them */
|
|
Packit |
549fdc |
while (*p != 0) {
|
|
Packit |
549fdc |
if (*p == '+' && (*(p - 1) != '\\'))
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* remove spaces from the end */
|
|
Packit |
549fdc |
while(val->size > 0 && c_isspace(val->data[val->size-1])) {
|
|
Packit |
549fdc |
if (val->size-2 > 0 && val->data[val->size-2] == '\\')
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
val->size--;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (val->size == 0 || name->size == 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
typedef struct elem_list_st {
|
|
Packit |
549fdc |
gnutls_datum_t name;
|
|
Packit |
549fdc |
gnutls_datum_t val;
|
|
Packit |
549fdc |
const char *pos;
|
|
Packit |
549fdc |
unsigned is_raw;
|
|
Packit |
549fdc |
struct elem_list_st *next;
|
|
Packit |
549fdc |
} elem_list_st;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static int add_new_elem(elem_list_st **head, const gnutls_datum_t *name, const gnutls_datum_t *val, const char *pos, unsigned is_raw)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
elem_list_st *elem = gnutls_malloc(sizeof(*elem));
|
|
Packit |
549fdc |
if (elem == NULL)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
memcpy(&elem->name, name, sizeof(*name));
|
|
Packit |
549fdc |
memcpy(&elem->val, val, sizeof(*val));
|
|
Packit |
549fdc |
elem->pos = pos;
|
|
Packit |
549fdc |
elem->is_raw = is_raw;
|
|
Packit |
549fdc |
elem->next = *head;
|
|
Packit |
549fdc |
*head = elem;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static int
|
|
Packit |
549fdc |
crt_set_dn(set_dn_func f, void *crt, const char *dn, const char **err)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
const char *p = dn;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
gnutls_datum_t name, val;
|
|
Packit |
549fdc |
unsigned is_raw;
|
|
Packit |
549fdc |
elem_list_st *list = NULL, *plist, *next;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (crt == NULL || dn == NULL)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* We parse the string and set all elements to a linked list in
|
|
Packit |
549fdc |
* reverse order. That way we can encode in reverse order,
|
|
Packit |
549fdc |
* the way RFC4514 requires. */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* For each element */
|
|
Packit |
549fdc |
while (*p != 0 && *p != '\n') {
|
|
Packit |
549fdc |
if (err)
|
|
Packit |
549fdc |
*err = p;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
is_raw = 0;
|
|
Packit |
549fdc |
ret = read_attr_and_val(&p, &name, &val, &is_raw);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* skip spaces and look for comma */
|
|
Packit |
549fdc |
while (c_isspace(*p))
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = add_new_elem(&list, &name, &val, p, is_raw);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (*p != ',' && *p != 0 && *p != '\n') {
|
|
Packit |
549fdc |
ret = gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
if (*p == ',')
|
|
Packit |
549fdc |
p++;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
plist = list;
|
|
Packit |
549fdc |
while(plist) {
|
|
Packit |
549fdc |
if (err)
|
|
Packit |
549fdc |
*err = plist->pos;
|
|
Packit |
549fdc |
ret = dn_attr_crt_set(f, crt, &plist->name, &plist->val, plist->is_raw);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
plist = plist->next;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = 0;
|
|
Packit |
549fdc |
fail:
|
|
Packit |
549fdc |
plist = list;
|
|
Packit |
549fdc |
while(plist) {
|
|
Packit |
549fdc |
next = plist->next;
|
|
Packit |
549fdc |
gnutls_free(plist);
|
|
Packit |
549fdc |
plist = next;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crt_set_dn:
|
|
Packit |
549fdc |
* @crt: a certificate of type #gnutls_x509_crt_t
|
|
Packit |
549fdc |
* @dn: a comma separated DN string (RFC4514)
|
|
Packit |
549fdc |
* @err: indicates the error position (if any)
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will set the DN on the provided certificate.
|
|
Packit |
549fdc |
* The input string should be plain ASCII or UTF-8 encoded. On
|
|
Packit |
549fdc |
* DN parsing error %GNUTLS_E_PARSING_ERROR is returned.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Note that DNs are not expected to hold DNS information, and thus
|
|
Packit |
549fdc |
* no automatic IDNA conversions are attempted when using this function.
|
|
Packit |
549fdc |
* If that is required (e.g., store a domain in CN), process the corresponding
|
|
Packit |
549fdc |
* input with gnutls_idna_map().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_crt_set_dn(gnutls_x509_crt_t crt, const char *dn,
|
|
Packit |
549fdc |
const char **err)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return crt_set_dn((set_dn_func) gnutls_x509_crt_set_dn_by_oid, crt,
|
|
Packit |
549fdc |
dn, err);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crt_set_issuer_dn:
|
|
Packit |
549fdc |
* @crt: a certificate of type #gnutls_x509_crt_t
|
|
Packit |
549fdc |
* @dn: a comma separated DN string (RFC4514)
|
|
Packit |
549fdc |
* @err: indicates the error position (if any)
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will set the DN on the provided certificate.
|
|
Packit |
549fdc |
* The input string should be plain ASCII or UTF-8 encoded. On
|
|
Packit |
549fdc |
* DN parsing error %GNUTLS_E_PARSING_ERROR is returned.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_crt_set_issuer_dn(gnutls_x509_crt_t crt, const char *dn,
|
|
Packit |
549fdc |
const char **err)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return crt_set_dn((set_dn_func)
|
|
Packit |
549fdc |
gnutls_x509_crt_set_issuer_dn_by_oid, crt, dn,
|
|
Packit |
549fdc |
err);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crq_set_dn:
|
|
Packit |
549fdc |
* @crq: a certificate of type #gnutls_x509_crq_t
|
|
Packit |
549fdc |
* @dn: a comma separated DN string (RFC4514)
|
|
Packit |
549fdc |
* @err: indicates the error position (if any)
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will set the DN on the provided certificate.
|
|
Packit |
549fdc |
* The input string should be plain ASCII or UTF-8 encoded. On
|
|
Packit |
549fdc |
* DN parsing error %GNUTLS_E_PARSING_ERROR is returned.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_crq_set_dn(gnutls_x509_crq_t crq, const char *dn,
|
|
Packit |
549fdc |
const char **err)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return crt_set_dn((set_dn_func) gnutls_x509_crq_set_dn_by_oid, crq,
|
|
Packit |
549fdc |
dn, err);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static
|
|
Packit |
549fdc |
int set_dn_by_oid(gnutls_x509_dn_t dn, const char *oid, unsigned int raw_flag, const void *name, unsigned name_size)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return _gnutls_x509_set_dn_oid(dn->asn, "", oid, raw_flag, name, name_size);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_set_str:
|
|
Packit |
549fdc |
* @dn: a pointer to DN
|
|
Packit |
549fdc |
* @str: a comma separated DN string (RFC4514)
|
|
Packit |
549fdc |
* @err: indicates the error position (if any)
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will set the DN on the provided DN structure.
|
|
Packit |
549fdc |
* The input string should be plain ASCII or UTF-8 encoded. On
|
|
Packit |
549fdc |
* DN parsing error %GNUTLS_E_PARSING_ERROR is returned.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.5.3
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_dn_set_str(gnutls_x509_dn_t dn, const char *str, const char **err)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (dn == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return crt_set_dn((set_dn_func) set_dn_by_oid, dn,
|
|
Packit |
549fdc |
str, err);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_init:
|
|
Packit |
549fdc |
* @dn: the object to be initialized
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function initializes a #gnutls_x509_dn_t type.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The object returned must be deallocated using
|
|
Packit |
549fdc |
* gnutls_x509_dn_deinit().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 2.4.0
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int gnutls_x509_dn_init(gnutls_x509_dn_t * dn)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int result;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
*dn = gnutls_calloc(1, sizeof(gnutls_x509_dn_st));
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if ((result =
|
|
Packit |
549fdc |
asn1_create_element(_gnutls_get_pkix(),
|
|
Packit |
549fdc |
"PKIX1.Name", &(*dn)->asn)) != ASN1_SUCCESS) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
gnutls_free(*dn);
|
|
Packit |
549fdc |
return _gnutls_asn2err(result);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_import:
|
|
Packit |
549fdc |
* @dn: the structure that will hold the imported DN
|
|
Packit |
549fdc |
* @data: should contain a DER encoded RDN sequence
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function parses an RDN sequence and stores the result to a
|
|
Packit |
549fdc |
* #gnutls_x509_dn_t type. The data must have been initialized
|
|
Packit |
549fdc |
* with gnutls_x509_dn_init(). You may use gnutls_x509_dn_get_rdn_ava() to
|
|
Packit |
549fdc |
* decode the DN.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 2.4.0
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int gnutls_x509_dn_import(gnutls_x509_dn_t dn, const gnutls_datum_t * data)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int result;
|
|
Packit |
549fdc |
char err[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (data->data == NULL || data->size == 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
result = _asn1_strict_der_decode(&dn->asn,
|
|
Packit |
549fdc |
data->data, data->size, err);
|
|
Packit |
549fdc |
if (result != ASN1_SUCCESS) {
|
|
Packit |
549fdc |
/* couldn't decode DER */
|
|
Packit |
549fdc |
_gnutls_debug_log("ASN.1 Decoding error: %s\n", err);
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return _gnutls_asn2err(result);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_deinit:
|
|
Packit |
549fdc |
* @dn: a DN uint8_t object pointer.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function deallocates the DN object as returned by
|
|
Packit |
549fdc |
* gnutls_x509_dn_import().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 2.4.0
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
void gnutls_x509_dn_deinit(gnutls_x509_dn_t dn)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
asn1_delete_structure(&dn->asn);
|
|
Packit |
549fdc |
gnutls_free(dn);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_export:
|
|
Packit |
549fdc |
* @dn: Holds the uint8_t DN object
|
|
Packit |
549fdc |
* @format: the format of output params. One of PEM or DER.
|
|
Packit |
549fdc |
* @output_data: will contain a DN PEM or DER encoded
|
|
Packit |
549fdc |
* @output_data_size: holds the size of output_data (and will be
|
|
Packit |
549fdc |
* replaced by the actual size of parameters)
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will export the DN to DER or PEM format.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* If the buffer provided is not long enough to hold the output, then
|
|
Packit |
549fdc |
* *@output_data_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER
|
|
Packit |
549fdc |
* will be returned.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* If the structure is PEM encoded, it will have a header
|
|
Packit |
549fdc |
* of "BEGIN NAME".
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_dn_export(gnutls_x509_dn_t dn,
|
|
Packit |
549fdc |
gnutls_x509_crt_fmt_t format, void *output_data,
|
|
Packit |
549fdc |
size_t * output_data_size)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (dn == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return _gnutls_x509_export_int_named(dn->asn, "rdnSequence",
|
|
Packit |
549fdc |
format, "NAME",
|
|
Packit |
549fdc |
output_data,
|
|
Packit |
549fdc |
output_data_size);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_export2:
|
|
Packit |
549fdc |
* @dn: Holds the uint8_t DN object
|
|
Packit |
549fdc |
* @format: the format of output params. One of PEM or DER.
|
|
Packit |
549fdc |
* @out: will contain a DN PEM or DER encoded
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will export the DN to DER or PEM format.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The output buffer is allocated using gnutls_malloc().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* If the structure is PEM encoded, it will have a header
|
|
Packit |
549fdc |
* of "BEGIN NAME".
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.1.3
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_dn_export2(gnutls_x509_dn_t dn,
|
|
Packit |
549fdc |
gnutls_x509_crt_fmt_t format, gnutls_datum_t * out)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (dn == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return _gnutls_x509_export_int_named2(dn->asn, "rdnSequence",
|
|
Packit |
549fdc |
format, "NAME", out);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_get_rdn_ava:
|
|
Packit |
549fdc |
* @dn: a pointer to DN
|
|
Packit |
549fdc |
* @irdn: index of RDN
|
|
Packit |
549fdc |
* @iava: index of AVA.
|
|
Packit |
549fdc |
* @ava: Pointer to structure which will hold output information.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Get pointers to data within the DN. The format of the @ava structure
|
|
Packit |
549fdc |
* is shown below.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* struct gnutls_x509_ava_st {
|
|
Packit |
549fdc |
* gnutls_datum_t oid;
|
|
Packit |
549fdc |
* gnutls_datum_t value;
|
|
Packit |
549fdc |
* unsigned long value_tag;
|
|
Packit |
549fdc |
* };
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The X.509 distinguished name is a sequence of sequences of strings
|
|
Packit |
549fdc |
* and this is what the @irdn and @iava indexes model.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Note that @ava will contain pointers into the @dn structure which
|
|
Packit |
549fdc |
* in turns points to the original certificate. Thus you should not
|
|
Packit |
549fdc |
* modify any data or deallocate any of those.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This is a low-level function that requires the caller to do the
|
|
Packit |
549fdc |
* value conversions when necessary (e.g. from UCS-2).
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: Returns 0 on success, or an error code.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_dn_get_rdn_ava(gnutls_x509_dn_t dn,
|
|
Packit |
549fdc |
int irdn, int iava, gnutls_x509_ava_st * ava)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
ASN1_TYPE rdn, elem;
|
|
Packit |
549fdc |
ASN1_DATA_NODE vnode;
|
|
Packit |
549fdc |
long len;
|
|
Packit |
549fdc |
int lenlen, remlen, ret;
|
|
Packit |
549fdc |
char rbuf[MAX_NAME_SIZE];
|
|
Packit |
549fdc |
unsigned char cls;
|
|
Packit |
549fdc |
const unsigned char *ptr;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
iava++;
|
|
Packit |
549fdc |
irdn++; /* 0->1, 1->2 etc */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
snprintf(rbuf, sizeof(rbuf), "rdnSequence.?%d.?%d", irdn, iava);
|
|
Packit |
549fdc |
rdn = asn1_find_node(dn->asn, rbuf);
|
|
Packit |
549fdc |
if (!rdn) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
snprintf(rbuf, sizeof(rbuf), "?%d.type", iava);
|
|
Packit |
549fdc |
elem = asn1_find_node(rdn, rbuf);
|
|
Packit |
549fdc |
if (!elem) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = asn1_read_node_value(elem, &vnode);
|
|
Packit |
549fdc |
if (ret != ASN1_SUCCESS) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ava->oid.data = (void *) vnode.value;
|
|
Packit |
549fdc |
ava->oid.size = vnode.value_len;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
snprintf(rbuf, sizeof(rbuf), "?%d.value", iava);
|
|
Packit |
549fdc |
elem = asn1_find_node(rdn, rbuf);
|
|
Packit |
549fdc |
if (!elem) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = asn1_read_node_value(elem, &vnode);
|
|
Packit |
549fdc |
if (ret != ASN1_SUCCESS) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
/* The value still has the previous tag's length bytes, plus the
|
|
Packit |
549fdc |
* current value's tag and length bytes. Decode them.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ptr = vnode.value;
|
|
Packit |
549fdc |
remlen = vnode.value_len;
|
|
Packit |
549fdc |
len = asn1_get_length_der(ptr, remlen, &lenlen);
|
|
Packit |
549fdc |
if (len < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_DER_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ptr += lenlen;
|
|
Packit |
549fdc |
remlen -= lenlen;
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
asn1_get_tag_der(ptr, remlen, &cls, &lenlen, &ava->value_tag);
|
|
Packit |
549fdc |
if (ret) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return _gnutls_asn2err(ret);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ptr += lenlen;
|
|
Packit |
549fdc |
remlen -= lenlen;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
signed long tmp;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
tmp = asn1_get_length_der(ptr, remlen, &lenlen);
|
|
Packit |
549fdc |
if (tmp < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_ASN1_DER_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
ava->value.size = tmp;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
ava->value.data = (void *) (ptr + lenlen);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_get_str:
|
|
Packit |
549fdc |
* @dn: a pointer to DN
|
|
Packit |
549fdc |
* @str: a datum that will hold the name
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will allocate buffer and copy the name in the provided DN.
|
|
Packit |
549fdc |
* The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
|
|
Packit |
549fdc |
* described in RFC4514. The output string will be ASCII or UTF-8
|
|
Packit |
549fdc |
* encoded, depending on the certificate data.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.4.2
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_dn_get_str(gnutls_x509_dn_t dn, gnutls_datum_t *str)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (dn == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return _gnutls_x509_get_dn(dn->asn, "rdnSequence", str, GNUTLS_X509_DN_FLAG_COMPAT);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_dn_get_str:
|
|
Packit |
549fdc |
* @dn: a pointer to DN
|
|
Packit |
549fdc |
* @str: a datum that will hold the name
|
|
Packit |
549fdc |
* @flags: zero or %GNUTLS_X509_DN_FLAG_COMPAT
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will allocate buffer and copy the name in the provided DN.
|
|
Packit |
549fdc |
* The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
|
|
Packit |
549fdc |
* described in RFC4514. The output string will be ASCII or UTF-8
|
|
Packit |
549fdc |
* encoded, depending on the certificate data.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* When the flag %GNUTLS_X509_DN_FLAG_COMPAT is specified, the output
|
|
Packit |
549fdc |
* format will match the format output by previous to 3.5.6 versions of GnuTLS
|
|
Packit |
549fdc |
* which was not not fully RFC4514-compliant.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Since: 3.5.7
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_dn_get_str2(gnutls_x509_dn_t dn, gnutls_datum_t *str, unsigned flags)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (dn == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_INVALID_REQUEST;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return _gnutls_x509_get_dn(dn->asn, "rdnSequence", str, flags);
|
|
Packit |
549fdc |
}
|